Files
vhdl/lib/models/memory/flash/serial/S25fl128k/model/s25fl128k.vhd
T
jens 2edaa4d7cb - added models
git-svn-id: http://moon:8086/svn/vhdl/trunk@1290 cc03376c-175c-47c8-b038-4cd826a8556b
2015-06-10 19:27:35 +00:00

3787 lines
178 KiB
VHDL

-------------------------------------------------------------------------------
-- File Name: s25fl128k.vhd
-------------------------------------------------------------------------------
-- Copyright (C) 2010 Spansion, LLC.
--
-- MODIFICATION HISTORY:
--
-- version: | author: | mod date: | changes made:
-- V1.0 R. Prokopovic 10 Oct 08 Inital Release
-------------------------------------------------------------------------------
-- PART DESCRIPTION:
--
-- Library: FLASH
-- Technology: FLASH MEMORY
-- Part: S25FL128K
--
-- Description: 128 Megabit Serial Flash Memory
--
-------------------------------------------------------------------------------
-- Known Bugs:
--
-------------------------------------------------------------------------------
LIBRARY IEEE; USE IEEE.std_logic_1164.ALL;
USE STD.textio.ALL;
USE IEEE.VITAL_timing.ALL;
USE IEEE.VITAL_primitives.ALL;
LIBRARY FMF; USE FMF.gen_utils.ALL;
USE FMF.conversions.ALL;
-------------------------------------------------------------------------------
-- ENTITY DECLARATION
-------------------------------------------------------------------------------
ENTITY s25fl128k IS
GENERIC (
---------------------------------------------------------------------------
-- TIMING GENERICS:
---------------------------------------------------------------------------
-- tipd delays: interconnect path delays (delay between components)
-- There should be one for each IN or INOUT pin in the port list
-- They are given default values of zero delay.
tipd_SCK : VitalDelayType01 := VitalZeroDelay01;
tipd_SI : VitalDelayType01 := VitalZeroDelay01;
tipd_SO : VitalDelayType01 := VitalZeroDelay01;
tipd_CSNeg : VitalDelayType01 := VitalZeroDelay01;
tipd_HOLDNeg : VitalDelayType01 := VitalZeroDelay01;
tipd_WPNeg : VitalDelayType01 := VitalZeroDelay01;
-- tpd delays: propagation delays (pin-to-pin delay within a component)
tpd_SCK_SO_RDID_EQ_0 : VitalDelayType01Z := UnitDelay01Z;--tCLQV1
tpd_SCK_SO_RDID_EQ_1 : VitalDelayType01Z := UnitDelay01Z;--tCLQV2
tpd_CSNeg_SO : VitalDelayType01Z := UnitDelay01Z;--tSHQZ
tpd_HOLDNeg_SO : VitalDelayType01Z := UnitDelay01Z;--tHLQZ
-- tsetup values: setup times
tsetup_CSNeg_SCK : VitalDelayType := UnitDelay;--tSLCH,tSHCH
tsetup_SI_SCK_normal_noedge_posedge : VitalDelayType
:= UnitDelay;--tDVCH
tsetup_HOLDNeg_SCK : VitalDelayType := UnitDelay;--tHLCH,tHHCH
tsetup_WPNeg_CSNeg : VitalDelayType := UnitDelay;--tWHSL
-- thold values: hold times
thold_CSNeg_SCK : VitalDelayType := UnitDelay;--tSLCH,tSHCH
thold_SI_SCK_normal_noedge_posedge : VitalDelayType
:= UnitDelay;--tCHDX
thold_HOLDNeg_SCK : VitalDelayType := UnitDelay;--tCHHL,tCHHH
thold_WPNeg_CSNeg : VitalDelayType := UnitDelay;--tSHWL
--tpw values: pulse width
tpw_SCK_slow_posedge : VitalDelayType := UnitDelay; -- tCH
tpw_SCK_slow_negedge : VitalDelayType := UnitDelay; -- tCL
tpw_SCK_fast_posedge : VitalDelayType := UnitDelay; -- tCH
tpw_SCK_fast_negedge : VitalDelayType := UnitDelay; -- tCL
tpw_SCK_quad_posedge : VitalDelayType := UnitDelay; -- tCH
tpw_SCK_quad_negedge : VitalDelayType := UnitDelay; -- tCL
tpw_CSNeg_read_posedge : VitalDelayType := UnitDelay; -- tSHSL1
tpw_CSNeg_pger_posedge : VitalDelayType := UnitDelay; -- tSHSL2
-- tperiod min (calculated as 1/max freq)
tperiod_SCK_slow : VitalDelayType := UnitDelay;--
tperiod_SCK_fast : VitalDelayType := UnitDelay;--
tperiod_SCK_quad : VitalDelayType := UnitDelay;--
-- tdevice values: values for internal delays
-- VCC (min) to CS# Low
tdevice_PU : VitalDelayType := 10 us;
-- CS# High to Power Down Mode -- tDP
tdevice_DP : VitalDelayType := 3 us;
-- CS# High to StandBy mode without Electronic Signature read
tdevice_RES1 : VitalDelayType := 3 us;
-- CS# High to StandBy mode with Electronic Signature read
tdevice_RES2 : VitalDelayType := 1.8 us;
-- CS# High to next Instruction after Suspend
tdevice_PRGSUSP : VitalDelayType := 20 us;
-- CS# High to next Instruction after Suspend
tdevice_ERSSUSP : VitalDelayType := 20 us;
-- CS# High to next Instruction after Suspend
tdevice_SUSP_DLY : VitalDelayType := 20 us;
-- Resume Suspend to Program/Erase time
tdevice_PRGRES : VitalDelayType := 200 ns;
-- Resume Suspend to Program/Erase time
tdevice_ERSRES : VitalDelayType := 200 ns;
-- Page Program Time
tdevice_PP : VitalDelayType := 3 ms;
-- Byte Program Time (First Byte)
tdevice_BP1 : VitalDelayType := 50 us;
-- Additional Byte Program Time (After First Byte)
tdevice_BP2 : VitalDelayType := 12 us;
-- Sector Erase Time (4KB)
tdevice_SE : VitalDelayType := 400 ms;
-- Block Erase Time (32KB)
tdevice_BE1 : VitalDelayType := 800 ms;
-- Block Erase Time (64KB)
tdevice_BE2 : VitalDelayType := 1000 ms;
-- Chip Erase Time
tdevice_CE : VitalDelayType := 40 sec;
-- Write Status Register Time
tdevice_WRR : VitalDelayType := 15 ms;
-- Write Volatile Status Register Time
tdevice_VRR : VitalDelayType := 50 ns;
---------------------------------------------------------------------------
-- CONTROL GENERICS:
---------------------------------------------------------------------------
-- generic control parameters
InstancePath : STRING := DefaultInstancePath;
TimingChecksOn : BOOLEAN := DefaultTimingChecks;
MsgOn : BOOLEAN := DefaultMsgOn;
XOn : BOOLEAN := DefaultXon;
-- memory file to be loaded
mem_file_name : STRING := "s25fl128k.mem";
screg_file_name : STRING := "s25fl128kscreg.mem";
UserPreload : BOOLEAN := FALSE; --TRUE;
LongTimming : BOOLEAN := TRUE;
-- For FMF SDF technology file usage
TimingModel : STRING := DefaultTimingModel
);
PORT (
-- Data Inputs/Outputs
SI : INOUT std_ulogic := 'U'; -- serial data input/IO0
SO : INOUT std_ulogic := 'U'; -- serial data output/IO1
-- Controls
SCK : IN std_ulogic := 'U'; -- serial clock input
CSNeg : IN std_ulogic := 'U'; -- chip select input
WPNeg : INOUT std_ulogic := 'U'; -- write protect input/IO2
HOLDNeg : INOUT std_ulogic := 'U' -- hold input/IO3
);
ATTRIBUTE VITAL_LEVEL0 of s25fl128k : ENTITY IS TRUE;
END s25fl128k;
-------------------------------------------------------------------------------
-- ARCHITECTURE DECLARATION
-------------------------------------------------------------------------------
ARCHITECTURE vhdl_behavioral of s25fl128k IS
ATTRIBUTE VITAL_LEVEL0 OF vhdl_behavioral : ARCHITECTURE IS TRUE;
---------------------------------------------------------------------------
-- CONSTANT AND SIGNAL DECLARATION
---------------------------------------------------------------------------
--Declaration of constants - memory characteristics
-- The constant declared here are used to enable the creation of models
-- of memories within a family with a minimum amount of editing
CONSTANT PartID : STRING := "s25fl128k";
CONSTANT MaxData : NATURAL := 16#FF#;
CONSTANT AddrRANGE : NATURAL := 16#FFFFFF#;
CONSTANT PageNum : NATURAL := 16#FFFF#;
CONSTANT SecSize_4 : NATURAL := 16#FFF#;
CONSTANT SecSize_32 : NATURAL := 16#7FFF#;
CONSTANT SecSize_64 : NATURAL := 16#FFFF#;
CONSTANT Blk_4_Num : NATURAL := 4095;
CONSTANT Blk_64_Num : NATURAL := 255;
CONSTANT Blk_32_Num : NATURAL := 511;
CONSTANT SFDP_HiAddr : NATURAL := 16#FF#;
CONSTANT SFDP_LoAddr : NATURAL := 16#00#;
CONSTANT SecReg_HiAddr : NATURAL := 16#FF#;
CONSTANT SecReg_LoAddr : NATURAL := 16#00#;
CONSTANT SCREG_LoAddr : NATURAL := 16#000#;
CONSTANT SCREG_HiAddr : NATURAL := 16#2FF#;
CONSTANT BYTE : NATURAL := 8;
-- Manufacturer Identification and Device Identification
CONSTANT Manuf_ID : NATURAL := 16#EF#;
CONSTANT Device_ID1 : NATURAL := 16#17#;
CONSTANT Device_ID2 : NATURAL := 16#40#;
CONSTANT Device_ID3 : NATURAL := 16#18#;
CONSTANT Unique_id_1 : NATURAL := 16#ABAB#;--this is 64bit ID number
CONSTANT Unique_id_2 : NATURAL := 16#00#;--this is 64bit ID number
-- Declaration of signals that will hold the delayed values of ports
SIGNAL SI_ipd : std_ulogic := 'U';
SIGNAL SO_ipd : std_ulogic := 'U';
SIGNAL SCK_ipd : std_ulogic := 'U';
SIGNAL CSNeg_ipd : std_ulogic := 'U';
SIGNAL WPNeg_ipd : std_ulogic := 'U';
SIGNAL HOLDNeg_ipd : std_ulogic := 'U';
SIGNAL HOLDNeg_pullup : std_ulogic := 'U';
SIGNAL WPNeg_pullup : std_ulogic := 'U';
-- internal delays
SIGNAL PP_in : std_ulogic := '0';
SIGNAL PP_out : std_ulogic := '0';
SIGNAL BP1_in : std_ulogic := '0';
SIGNAL BP1_out : std_ulogic := '0';
SIGNAL BP2_in : std_ulogic := '0';
SIGNAL BP2_out : std_ulogic := '0';
SIGNAL SE_in : std_ulogic := '0';
SIGNAL SE_out : std_ulogic := '0';
SIGNAL BE1_in : std_ulogic := '0';
SIGNAL BE1_out : std_ulogic := '0';
SIGNAL BE2_in : std_ulogic := '0';
SIGNAL BE2_out : std_ulogic := '0';
SIGNAL CE_in : std_ulogic := '0';
SIGNAL CE_out : std_ulogic := '0';
SIGNAL WRR_in : std_ulogic := '0';
SIGNAL WRR_out : std_ulogic := '0';
SIGNAL ERSSUSP_in : std_ulogic := '0';
SIGNAL ERSSUSP_out : std_ulogic := '0';
SIGNAL ERSRES_in : std_ulogic := '0';
SIGNAL ERSRES_out : std_ulogic := '0';
SIGNAL PRGSUSP_in : std_ulogic := '0';
SIGNAL PRGSUSP_out : std_ulogic := '0';
SIGNAL PRGRES_in : std_ulogic := '0';
SIGNAL PRGRES_out : std_ulogic := '0';
SIGNAL PU_in : std_ulogic := '0';
SIGNAL PU_out : std_ulogic := '0';
SIGNAL RES1_in : std_ulogic := '0';
SIGNAL RES1_out : std_ulogic := '0';
SIGNAL RES2_in : std_ulogic := '0';
SIGNAL RES2_out : std_ulogic := '0';
SIGNAL DP_in : std_ulogic := '0';
SIGNAL DP_out : std_ulogic := '0';
SIGNAL SUSP_FL_IN : std_ulogic := '0';
SIGNAL SUSP_FL_OUT : std_ulogic := '0';
BEGIN
---------------------------------------------------------------------------
-- Internal Delays
---------------------------------------------------------------------------
-- Artificial VITAL primitives to incorporate internal delays
-- Because a tdevice generics is used, there must be a VITAL_primitives
-- assotiated with them
PP :VitalBuf(PP_out, PP_in, (tdevice_PP ,UnitDelay));
BP1 :VitalBuf(BP1_out, BP1_in, (tdevice_BP1 ,UnitDelay));
BP2 :VitalBuf(BP2_out, BP2_in, (tdevice_BP2 ,UnitDelay));
SE :VitalBuf(SE_out, SE_in, (tdevice_SE ,UnitDelay));
BE1 :VitalBuf(BE1_out, BE1_in, (tdevice_BE1 ,UnitDelay));
BE2 :VitalBuf(BE2_out, BE2_in, (tdevice_BE2 ,UnitDelay));
WRR :VitalBuf(WRR_out, WRR_in, (tdevice_WRR ,UnitDelay));
ERSSUSP :VitalBuf(ERSSUSP_out, ERSSUSP_in, (tdevice_ERSSUSP ,UnitDelay));
ERSRES :VitalBuf(ERSRES_out, ERSRES_in, (tdevice_ERSRES ,UnitDelay));
PRGSUSP :VitalBuf(PRGSUSP_out, PRGSUSP_in, (tdevice_PRGSUSP ,UnitDelay));
PRGRES :VitalBuf(PRGRES_out, PRGRES_in, (tdevice_PRGRES ,UnitDelay));
PU :VitalBuf(PU_out, PU_in, (tdevice_PU ,UnitDelay));
RES1 :VitalBuf(RES1_out, RES1_in, (tdevice_RES1 ,UnitDelay));
CE :VitalBuf(CE_out, CE_in, (tdevice_CE ,UnitDelay));
DP :VitalBuf(DP_out, DP_in, (tdevice_DP ,UnitDelay));
RES2 :VitalBuf(RES2_out, RES2_in, (tdevice_RES2 ,UnitDelay));
SUSP_DLY :VitalBuf(SUSP_FL_OUT, SUSP_FL_IN, (tdevice_SUSP_DLY,UnitDelay));
---------------------------------------------------------------------------
-- Wire Delays
---------------------------------------------------------------------------
WireDelay : BLOCK
BEGIN
w_1 : VitalWireDelay (SI_ipd, SI, tipd_SI);
w_2 : VitalWireDelay (SO_ipd, SO, tipd_SO);
w_3 : VitalWireDelay (SCK_ipd, SCK, tipd_SCK);
w_4 : VitalWireDelay (CSNeg_ipd, CSNeg, tipd_CSNeg);
w_6 : VitalWireDelay (WPNeg_ipd, WPNeg, tipd_WPNeg);
w_7 : VitalWireDelay (HOLDNeg_ipd, HOLDNeg, tipd_HOLDNeg);
END BLOCK;
---------------------------------------------------------------------------
-- Main Behavior Block
---------------------------------------------------------------------------
Behavior: BLOCK
PORT (
SIIn : IN std_ulogic := 'U';
SIOut : OUT std_ulogic := 'U';
SOIn : IN std_logic := 'U';
SOut : OUT std_logic := 'U';
SCK : IN std_ulogic := 'U';
CSNeg : IN std_ulogic := 'U';
HOLDNegIn : IN std_ulogic := 'U';
HOLDNegOut : OUT std_ulogic := 'U';
WPNegIn : IN std_ulogic := 'U';
WPNegOut : OUT std_ulogic := 'U'
);
PORT MAP (
SIIn => SI_ipd,
SIOut => SI,
SOIn => SO_ipd,
SOut => SO,
SCK => SCK_ipd,
CSNeg => CSNeg_ipd,
HOLDNegIn => HOLDNeg_ipd,
HOLDNegOut => HOLDNeg,
WPNegIn => WPNeg_ipd,
WPNegOut => WPNeg
);
-- State Machine : State_Type
TYPE state_type IS (IDLE,
WRITE_SR,
PAGE_PG,
PG_SUSP,
SECTOR_ERS,
BULK_ERS,
ERS_SUSP,
ERS_SUSP_PG,
PG_SUSP_ERS,
DP_DOWN,
WRITE_SR_V
);
-- Instruction Type
TYPE instruction_type IS ( NONE,
WREN , -- 06h
WRENV , -- 50h
WRDI , -- 04h
RDSR , -- 05h
RDSR2 , -- 35h
WRR , -- 01h
READ , -- 03h
FAST_READ , -- 0Bh
FAST_DREAD , -- 3Bh
FAST_QREAD , -- 6Bh
FAST_DREAD_2 , -- BBh
FAST_QREAD_4 , -- EBh
W_QREAD , -- E7h
WOCT_QREAD , -- E3h
SET_BURST_WRAP , -- 77h
CONT_RD_RST , -- FFh or FFFFH
PP , -- 02h
QPP , -- 32h
SE , -- 20h
BE_32 , -- 52h
BE_64 , -- D8h
CE , -- C7h or 60h
ERS_PG_SUSP , -- 75h
ERS_PG_RES , -- 7Ah
DP , -- B9h
RES_RD_ID , -- ABh
RDID , -- 90h
RDID_DUAL , -- 92h
RDID_QUAD , -- 94h
RD_UNIQ_ID , -- 4Bh
RDIDJ , -- 9Fh
RD_SFDP , -- 5Ah
ERS_SCREG , -- 44h
PG_SCREG , -- 42h
RD_SCREG -- 48h
);
TYPE WByteType IS ARRAY (0 TO 255) OF INTEGER RANGE -1 TO MaxData;
-- Flash Memory Array
TYPE MemArray IS ARRAY (0 TO AddrRANGE) OF INTEGER RANGE -1 TO MaxData;
-- SFDP Memory Array
TYPE SFDPArray IS ARRAY (SFDP_LoAddr TO SFDP_HiAddr) OF INTEGER
RANGE -1 TO MaxData;
-- Security Register Array
TYPE SCREGArray IS ARRAY (SecReg_LoAddr TO SecReg_HiAddr) OF INTEGER
RANGE -1 TO MaxData;
-----------------------------------------------------------------------
-- memory declaration
-----------------------------------------------------------------------
-- Memory
SHARED VARIABLE Mem : MemArray := (OTHERS => MaxData);
-- Security Register 1
SHARED VARIABLE Security_Reg1 : SCREGArray := (OTHERS => MaxData);
-- Security Register 2
SHARED VARIABLE Security_Reg2 : SCREGArray := (OTHERS => MaxData);
-- Security Register 3
SHARED VARIABLE Security_Reg3 : SCREGArray := (OTHERS => MaxData);
--SFDP Array
SHARED VARIABLE SFDP_array : SFDPArray := (OTHERS => 0);
-- Programming Buffer
SIGNAL WByte : WByteType := (OTHERS => MaxData);
-- states
SIGNAL current_state : state_type;
SIGNAL next_state : state_type;
SIGNAL Instruct : instruction_type;
--zero delay signal
SIGNAL SOut_zd : std_logic := 'Z';
SIGNAL SIOut_zd : std_logic := 'Z';
SIGNAL HOLDNegOut_zd : std_logic := 'Z';
SIGNAL WPNegOut_zd : std_logic := 'Z';
--HOLD delay on output data
SIGNAL SOut_z : std_logic := 'Z';
SIGNAL SIOut_z : std_logic := 'Z';
-- powerup
SIGNAL PoweredUp : std_logic := '0';
-----------------------------------------------------------------------
-- Registers
-----------------------------------------------------------------------
-- Status register 1
SHARED VARIABLE Status_reg1 : std_logic_vector(7 downto 0)
:= (others => '0');
SIGNAL Status_reg1_in : std_logic_vector(7 downto 0)
:= (others => '0');
-- Status Register Protect Bit 0
ALIAS SRP0 :std_logic IS Status_reg1(7);
-- Sector/Block protect bit
ALIAS SEC :std_logic IS Status_reg1(6);
-- Top Bottom Bit
ALIAS TB :std_logic IS Status_reg1(5);
-- Status Register Block Protection Bits
ALIAS BP2 :std_logic IS Status_reg1(4);
ALIAS BP1 :std_logic IS Status_reg1(3);
ALIAS BP0 :std_logic IS Status_reg1(2);
-- Status Register Write Enable Latch Bit
ALIAS WEL :std_logic IS Status_reg1(1);
-- Status Register Busy Bit
ALIAS BUSY :std_logic IS Status_reg1(0);
-- Status register 2
SHARED VARIABLE Status_reg2 : std_logic_vector(7 downto 0)
:= (others => '0');
SIGNAL Status_reg2_in : std_logic_vector(7 downto 0)
:= (others => '0');
-- Suspend status bit
ALIAS SUS :std_logic IS Status_reg2(7);
-- Complement protect bit
ALIAS CMP :std_logic IS Status_reg2(6);
-- Security Register Lock bits
ALIAS LB3 :std_logic IS Status_reg2(5);
ALIAS LB2 :std_logic IS Status_reg2(4);
ALIAS LB1 :std_logic IS Status_reg2(3);
-- Quad enable bit
ALIAS QE :std_logic IS Status_reg2(1);
-- Status register protect bit
ALIAS SRP1 :std_logic IS Status_reg2(0);
-- Sector is protect if Sec_Prot(Blk_4_Num) = '1'
SHARED VARIABLE Sec_Prot : std_logic_vector(Blk_4_Num downto 0) :=
(OTHERS => '0');
--Command Register
SIGNAL write : std_logic := '0';
SIGNAL read_out : std_logic := '0';
SIGNAL pg_screg_flag : boolean := false;
SIGNAL ers_screg_flag : boolean := false;
SIGNAL slow_read : boolean := false;
SIGNAL dual_read : boolean := false;
SIGNAL fast_rd : boolean := true;
SIGNAL quad_read : boolean := false;
SIGNAL read_id : boolean := false;
SIGNAL sr_read : boolean := false;
SHARED VARIABLE pp_quad : boolean := false;
SHARED VARIABLE hold_mode : boolean := false;
SHARED VARIABLE res_flag : boolean := false;
SHARED VARIABLE wren_vlt_flag : boolean := false;
--FSM control signals
SIGNAL PDONE : std_logic := '1';
SIGNAL PSTART : std_logic := '0';
SIGNAL PGSUSP : std_logic := '0';
SIGNAL PGRES : std_logic := '0';
SIGNAL WDONE : std_logic := '1';
SIGNAL WSTART : std_logic := '0';
SIGNAL VLTSTART : std_logic := '0';
SIGNAL VLTDONE : std_logic := '1';
SIGNAL EDONE : std_logic := '1';
SIGNAL ESTART : std_logic := '0';
SIGNAL ESUSP : std_logic := '0';
SIGNAL ERES : std_logic := '0';
SHARED VARIABLE read_cnt : NATURAL := 0;
SHARED VARIABLE read_addr : NATURAL RANGE 0 TO AddrRANGE ;
SHARED VARIABLE wrap_byte : std_logic_vector(7 downto 0);
SIGNAL change_addr : std_logic := '0';
SIGNAL Address : NATURAL RANGE 0 TO AddrRANGE := 0;
SIGNAL change_prot_bits : std_logic := '0';
SHARED VARIABLE BP_bits : std_logic_vector(2 downto 0) := "000";
SHARED VARIABLE LB_bits : std_logic_vector(2 downto 0) := "000";
SIGNAL Byte_number : NATURAL RANGE 0 TO 255 := 0;
-- Sector and subsector addresses
SIGNAL SA : NATURAL RANGE 0 TO Blk_4_Num := 0;
SHARED VARIABLE sect : NATURAL RANGE 0 TO Blk_4_Num;
SHARED VARIABLE sect_tmp_pg : NATURAL RANGE 0 TO Blk_4_Num;
SHARED VARIABLE sect_tmp_ers: NATURAL RANGE 0 TO Blk_4_Num;
SHARED VARIABLE w_size : NATURAL RANGE 0 TO 64;
-- timing check violation
SIGNAL Viol : X01 := '0';
PROCEDURE ADDRHILO_SEC64 (
VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to AddrRANGE;
VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to AddrRANGE;
VARIABLE Addr : NATURAL) IS
VARIABLE sector : NATURAL RANGE 0 TO Blk_64_Num;
BEGIN
sector := Addr/16#10000#;
AddrLOW := sector*16#10000#;
AddrHIGH := sector*16#10000# + 16#0FFFF#;
END ADDRHILO_SEC64;
PROCEDURE ADDRHILO_SEC32 (
VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to AddrRANGE;
VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to AddrRANGE;
VARIABLE Addr : NATURAL) IS
VARIABLE sector : NATURAL RANGE 0 TO Blk_32_Num;
BEGIN
sector := Addr/16#8000#;
AddrLOW := sector*16#8000#;
AddrHIGH := sector*16#8000# + 16#7FFF#;
END ADDRHILO_SEC32;
PROCEDURE ADDRHILO_SEC4 (
VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to AddrRANGE;
VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to AddrRANGE;
VARIABLE Addr : NATURAL) IS
VARIABLE sector : NATURAL RANGE 0 TO Blk_4_Num;
BEGIN
sector := Addr/16#1000#;
AddrLOW := sector*16#1000#;
AddrHIGH := sector*16#1000# + 16#0FFF#;
END ADDRHILO_SEC4;
PROCEDURE ADDRHILO_PG(
VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to AddrRANGE;
VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to AddrRANGE;
VARIABLE Addr : NATURAL) IS
VARIABLE page : NATURAL RANGE 0 TO PageNum;
BEGIN
page := Addr/16#100#;
AddrLOW := Page*16#100#;
AddrHIGH := Page*16#100# + 16#FF#;
END AddrHILO_PG;
PROCEDURE ADDRHILO_WRAP(
VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange;
VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange;
VARIABLE Address : NATURAL;
VARIABLE Wrap_size: NATURAL) IS
VARIABLE Addr_tmp : NATURAL;
VARIABLE Sect_wrap: NATURAL;
BEGIN
Addr_tmp := Address;
Sect_wrap := Addr_tmp/Wrap_size;
AddrLOW := Sect_wrap*Wrap_size;
AddrHIGH := Sect_wrap*Wrap_size + (Wrap_size - 1);
END ADDRHILO_WRAP;
BEGIN
---------------------------------------------------------------------------
--Power Up time
---------------------------------------------------------------------------
PoweredUp <= '1' AFTER tdevice_PU;
---------------------------------------------------------------------------
-- VITAL Timing Checks Procedures
---------------------------------------------------------------------------
VITALTimingCheck: PROCESS(SIIn,SOIn,SCK_ipd,CSNeg_ipd,HOLDNegIn,WPNegIn)
-- Timing Check Variables
-- Setup/Hold Checks variables
VARIABLE Tviol_CSNeg_SCK : X01 := '0';
VARIABLE TD_CSNeg_SCK : VitalTimingDataType;
VARIABLE Tviol_SI_SCK : X01 := '0';
VARIABLE TD_SI_SCK : VitalTimingDataType;
VARIABLE Tviol_SOIn_SCK : X01 := '0';
VARIABLE TD_SOIn_SCK : VitalTimingDataType;
VARIABLE Tviol_HOLDNeg_SCK : X01 := '0';
VARIABLE TD_HOLDNeg_SCK : VitalTimingDataType;
VARIABLE Tviol_HOLDNegIn_SCK : X01 := '0';
VARIABLE TD_HOLDNegIn_SCK : VitalTimingDataType;
VARIABLE Tviol_WPNegIn_SCK : X01 := '0';
VARIABLE TD_WPNegIn_SCK : VitalTimingDataType;
VARIABLE Tviol_WPNeg_CSNeg_setup : X01 := '0';
VARIABLE TD_WPNeg_CSNeg_setup : VitalTimingDataType;
VARIABLE Tviol_WPNeg_CSNeg_hold : X01 := '0';
VARIABLE TD_WPNeg_CSNeg_hold : VitalTimingDataType;
--Pulse Width and Period Check Variables
VARIABLE Pviol_SCK_slow : X01 := '0';
VARIABLE PD_SCK_slow : VitalPeriodDataType:= VitalPeriodDataInit;
VARIABLE Pviol_SCK_fast : X01 := '0';
VARIABLE PD_SCK_fast : VitalPeriodDataType:= VitalPeriodDataInit;
VARIABLE Pviol_SCK_quad : X01 := '0';
VARIABLE PD_SCK_quad : VitalPeriodDataType:= VitalPeriodDataInit;
VARIABLE Pviol_CSNeg_read : X01 := '0';
VARIABLE PD_CSNeg_read : VitalPeriodDataType:= VitalPeriodDataInit;
VARIABLE Pviol_CSNeg_pgers : X01 := '0';
VARIABLE PD_CSNeg_pgers : VitalPeriodDataType:= VitalPeriodDataInit;
VARIABLE Pviol_SCK_slow_p : X01 := '0';
VARIABLE PD_SCK_slow_p : VitalPeriodDataType:= VitalPeriodDataInit;
VARIABLE Pviol_SCK_fast_p : X01 := '0';
VARIABLE PD_SCK_fast_p : VitalPeriodDataType:= VitalPeriodDataInit;
VARIABLE Pviol_SCK_quad_p : X01 := '0';
VARIABLE PD_SCK_quad_p : VitalPeriodDataType:= VitalPeriodDataInit;
VARIABLE Violation : X01 := '0';
BEGIN
---------------------------------------------------------------------------
-- Timing Check Section
---------------------------------------------------------------------------
IF (TimingChecksOn) THEN
-- Setup/Hold Check between CS# and SCK
VitalSetupHoldCheck (
TestSignal => CSNeg_ipd,
TestSignalName => "CS#",
RefSignal => SCK_ipd,
RefSignalName => "SCK",
SetupHigh => tsetup_CSNeg_SCK,
SetupLow => tsetup_CSNeg_SCK,
HoldHigh => thold_CSNeg_SCK,
HoldLow => thold_CSNeg_SCK,
CheckEnabled => true,
RefTransition => '/',
HeaderMsg => InstancePath & PartID,
TimingData => TD_CSNeg_SCK,
Violation => Tviol_CSNeg_SCK
);
-- Setup/Hold Check between SI and SCK /
VitalSetupHoldCheck (
TestSignal => SIIn,
TestSignalName => "SI",
RefSignal => SCK_ipd,
RefSignalName => "SCK",
SetupHigh => tsetup_SI_SCK_normal_noedge_posedge,
SetupLow => tsetup_SI_SCK_normal_noedge_posedge,
HoldHigh => thold_SI_SCK_normal_noedge_posedge,
HoldLow => thold_SI_SCK_normal_noedge_posedge,
CheckEnabled => SIOut_z /= SIIn AND (NOT dual_read)
AND (NOT quad_read),
RefTransition => '/',
HeaderMsg => InstancePath & PartID,
TimingData => TD_SI_SCK,
Violation => Tviol_SI_SCK
);
VitalSetupHoldCheck (
TestSignal => SOIn,
TestSignalName => "SO",
RefSignal => SCK_ipd,
RefSignalName => "SCK",
SetupHigh => tsetup_SI_SCK_normal_noedge_posedge,
SetupLow => tsetup_SI_SCK_normal_noedge_posedge,
HoldHigh => thold_SI_SCK_normal_noedge_posedge,
HoldLow => thold_SI_SCK_normal_noedge_posedge,
CheckEnabled => SOut_z /= SOIn AND QE = '1'
AND (read_out = '0'),
RefTransition => '/',
HeaderMsg => InstancePath & PartID,
TimingData => TD_SOIn_SCK,
Violation => Tviol_SOIn_SCK
);
VitalSetupHoldCheck (
TestSignal => HOLDNegIn,
TestSignalName => "HOLD#",
RefSignal => SCK_ipd,
RefSignalName => "SCK",
SetupHigh => tsetup_SI_SCK_normal_noedge_posedge,
SetupLow => tsetup_SI_SCK_normal_noedge_posedge,
HoldHigh => thold_SI_SCK_normal_noedge_posedge,
HoldLow => thold_SI_SCK_normal_noedge_posedge,
CheckEnabled => HOLDNegOut_zd /= HOLDNegIn,
RefTransition => '/',
HeaderMsg => InstancePath & PartID,
TimingData => TD_HOLDNegIn_SCK,
Violation => Tviol_HOLDNegIn_SCK
);
VitalSetupHoldCheck (
TestSignal => WPNegIn,
TestSignalName => "WP#",
RefSignal => SCK_ipd,
RefSignalName => "SCK",
SetupHigh => tsetup_SI_SCK_normal_noedge_posedge,
SetupLow => tsetup_SI_SCK_normal_noedge_posedge,
HoldHigh => thold_SI_SCK_normal_noedge_posedge,
HoldLow => thold_SI_SCK_normal_noedge_posedge,
CheckEnabled => WPNegOut_zd /= WPNegIn,
RefTransition => '/',
HeaderMsg => InstancePath & PartID,
TimingData => TD_WPNegIn_SCK,
Violation => Tviol_WPNegIn_SCK
);
-- Setup/Hold Check between HOLD# and SCK /
VitalSetupHoldCheck (
TestSignal => HOLDNegIn,
TestSignalName => "HOLD#",
RefSignal => SCK_ipd,
RefSignalName => "SCK",
SetupHigh => tsetup_HOLDNeg_SCK,
SetupLow => tsetup_HOLDNeg_SCK,
HoldHigh => thold_HOLDNeg_SCK,
HoldLow => thold_HOLDNeg_SCK,
CheckEnabled => QE = '0' AND HOLDNegIn /= 'X',
RefTransition => '/',
HeaderMsg => InstancePath & PartID,
TimingData => TD_HOLDNeg_SCK,
Violation => Tviol_HOLDNeg_SCK
);
-- Setup Check between WP# and CS# \
VitalSetupHoldCheck (
TestSignal => WPNegIn,
TestSignalName => "WP#",
RefSignal => CSNeg_ipd,
RefSignalName => "CS#",
SetupHigh => tsetup_WPNeg_CSNeg,
CheckEnabled => QE = '0',
RefTransition => '\',
HeaderMsg => InstancePath & PartID,
TimingData => TD_WPNeg_CSNeg_setup,
Violation => Tviol_WPNeg_CSNeg_setup
);
-- Hold Check between WP# and CS# /
VitalSetupHoldCheck (
TestSignal => WPNegIn,
TestSignalName => "WP#",
RefSignal => CSNeg_ipd,
RefSignalName => "CS#",
HoldHigh => thold_WPNeg_CSNeg,
CheckEnabled => QE = '0',
RefTransition => '/',
HeaderMsg => InstancePath & PartID,
TimingData => TD_WPNeg_CSNeg_hold,
Violation => Tviol_WPNeg_CSNeg_hold
);
--Pulse Width and Period Check Variables
VitalPeriodPulseCheck (
TestSignal => SCK_ipd,
TestSignalName => "SCK",
PulseWidthLow => tpw_SCK_slow_negedge,
PulseWidthHigh => tpw_SCK_slow_posedge,
PeriodData => PD_SCK_slow,
XOn => XOn,
MsgOn => MsgOn,
Violation => Pviol_SCK_slow,
HeaderMsg => InstancePath & PartID,
CheckEnabled => slow_read
);
VitalPeriodPulseCheck (
TestSignal => SCK_ipd,
TestSignalName => "SCK",
PulseWidthLow => tpw_SCK_fast_negedge,
PulseWidthHigh => tpw_SCK_fast_posedge,
PeriodData => PD_SCK_fast,
XOn => XOn,
MsgOn => MsgOn,
Violation => Pviol_SCK_fast,
HeaderMsg => InstancePath & PartID,
CheckEnabled => fast_rd
);
VitalPeriodPulseCheck (
TestSignal => SCK_ipd,
TestSignalName => "SCK",
PulseWidthLow => tpw_SCK_quad_negedge,
PulseWidthHigh => tpw_SCK_quad_posedge,
PeriodData => PD_SCK_quad,
XOn => XOn,
MsgOn => MsgOn,
Violation => Pviol_SCK_quad,
HeaderMsg => InstancePath & PartID,
CheckEnabled => quad_read OR pp_quad
);
-- Pulse Width Check CS# for READ, serial mode
VitalPeriodPulseCheck (
TestSignal => CSNeg_ipd,
TestSignalName => "CS#",
PulseWidthHigh => tpw_CSNeg_read_posedge,
PeriodData => PD_CSNeg_read,
XOn => XOn,
MsgOn => MsgOn,
Violation => Pviol_CSNeg_read,
HeaderMsg => InstancePath & PartID,
CheckEnabled => slow_read OR fast_rd OR dual_read OR
quad_read
);
-- Pulse Width Check CS# for Program/Erase, serial mode
VitalPeriodPulseCheck (
TestSignal => CSNeg_ipd,
TestSignalName => "CS#",
PulseWidthHigh => tpw_CSNeg_pger_posedge,
PeriodData => PD_CSNeg_pgers,
XOn => XOn,
MsgOn => MsgOn,
Violation => Pviol_CSNeg_pgers,
HeaderMsg => InstancePath & PartID,
CheckEnabled => true);
-- Period Check SCK for READ, serial mode
VitalPeriodPulseCheck (
TestSignal => SCK_ipd,
TestSignalName => "SCK",
Period => tperiod_SCK_slow,
PeriodData => PD_SCK_slow_p,
XOn => XOn,
MsgOn => MsgOn,
Violation => Pviol_SCK_slow_p,
HeaderMsg => InstancePath & PartID,
CheckEnabled => slow_read
);
VitalPeriodPulseCheck (
TestSignal => SCK_ipd,
TestSignalName => "SCK",
Period => tperiod_SCK_fast,
PeriodData => PD_SCK_fast_p,
XOn => XOn,
MsgOn => MsgOn,
Violation => Pviol_SCK_fast_p,
HeaderMsg => InstancePath & PartID,
CheckEnabled => fast_rd OR dual_read
);
VitalPeriodPulseCheck (
TestSignal => SCK_ipd,
TestSignalName => "SCK",
Period => tperiod_SCK_quad,
PeriodData => PD_SCK_quad_p,
XOn => XOn,
MsgOn => MsgOn,
Violation => Pviol_SCK_quad_p,
HeaderMsg => InstancePath & PartID,
CheckEnabled => pp_quad OR quad_read
);
Violation := Tviol_CSNeg_SCK OR
Tviol_SI_SCK OR
Tviol_HOLDNeg_SCK OR
Tviol_WPNeg_CSNeg_setup OR
Tviol_WPNeg_CSNeg_hold OR
Tviol_HOLDNegIn_SCK OR
Tviol_WPNegIn_SCK OR
Tviol_SOIn_SCK OR
Pviol_SCK_slow OR
Pviol_SCK_fast OR
Pviol_CSNeg_read OR
Pviol_CSNeg_pgers OR
Pviol_SCK_slow_p OR
Pviol_SCK_fast_p OR
Pviol_SCK_quad_p OR
Pviol_SCK_quad;
Viol <= Violation;
ASSERT Violation = '0'
REPORT InstancePath & partID & ": simulation may be" &
" inaccurate due to timing violations"
SEVERITY WARNING;
END IF;
END PROCESS VITALTimingCheck;
---------------------------------------------------------------------------
-- sequential process for FSM state transition
---------------------------------------------------------------------------
StateTransition : PROCESS(next_state,PoweredUp)
BEGIN
IF PoweredUp = '1' THEN
IF next_state'EVENT THEN
current_state <= next_state;
END IF;
END IF;
END PROCESS StateTransition;
---------------------------------------------------------------------------
-- Write cycle decode
---------------------------------------------------------------------------
BusCycleDecode : PROCESS(SCK_ipd, CSNeg_ipd)
TYPE bus_cycle_type IS (STAND_BY,
OPCODE_BYTE,
ADDRESS_BYTES,
DUMMY_BYTES,
MODE_BYTE,
DATA_BYTES
);
TYPE quad_data_type IS ARRAY (0 TO 511) OF INTEGER RANGE 0 TO 15;
VARIABLE bus_cycle_state : bus_cycle_type;
VARIABLE opcode_cnt : NATURAL := 0;
VARIABLE addr_cnt : NATURAL := 0;
VARIABLE mode_cnt : NATURAL := 0;
VARIABLE wrap_cnt : NATURAL := 0;
VARIABLE dummy_cnt : NATURAL := 0;
VARIABLE data_cnt : NATURAL := 0;
VARIABLE bit_cnt : NATURAL := 0;
VARIABLE Data_in : std_logic_vector(2047 downto 0)
:= (others => '0');
VARIABLE opcode : std_logic_vector(7 downto 0);
VARIABLE opcode_in : std_logic_vector(7 downto 0);
VARIABLE opcode_double : std_logic_vector(15 downto 0);
VARIABLE opcode_double_in : std_logic_vector(15 downto 0);
VARIABLE addr_bytes : std_logic_vector(23 downto 0);
VARIABLE Address_in : std_logic_vector(23 downto 0);
VARIABLE mode_bits : std_logic_vector(7 downto 0);
VARIABLE mode_in : std_logic_vector(7 downto 0);
-- VARIABLE wrap_byte : std_logic_vector(7 downto 0);
VARIABLE wrap_in : std_logic_vector(7 downto 0);
VARIABLE quad_data_in : quad_data_type;
VARIABLE quad_nybble : std_logic_vector(3 downto 0);
VARIABLE Quad_slv : std_logic_vector(3 downto 0);
VARIABLE Byte_slv : std_logic_vector(7 downto 0);
BEGIN
IF falling_edge(CSNeg_ipd) THEN
IF (bus_cycle_state = STAND_BY) THEN
bus_cycle_state := OPCODE_BYTE;
Instruct <= NONE;
write <= '1';
opcode_cnt := 0;
addr_cnt := 0;
data_cnt := 0;
mode_cnt := 0;
wrap_cnt := 0;
dummy_cnt := 0;
ELSIF (bus_cycle_state = DATA_BYTES AND
mode_bits(5 DOWNTO 4) = "10") THEN
bus_cycle_state := ADDRESS_BYTES;
dummy_cnt := 0;
opcode_cnt := 0;
END IF;
END IF;
IF rising_edge(SCK_ipd) AND (PoweredUp = '1') THEN
IF (CSNeg_ipd = '0') THEN
CASE (bus_cycle_state) IS
WHEN OPCODE_BYTE =>
IF (HOLDNeg_pullup = '1' AND QE='0') OR QE='1' THEN
opcode_in(opcode_cnt) := SIIn;
opcode_cnt := opcode_cnt + 1;
IF opcode_cnt = BYTE THEN
FOR I IN 7 DOWNTO 0 LOOP
opcode(i) := opcode_in(7-i);
END LOOP;
CASE opcode IS
WHEN "00000110" => -- 06H
Instruct <= WREN;
bus_cycle_state := DATA_BYTES;
WHEN "01010000" =>
Instruct <= WRENV;
bus_cycle_state := DATA_BYTES;
WHEN "00000100" => --04h
Instruct <= WRDI;
bus_cycle_state := DATA_BYTES;
WHEN "00000101" => -- 05h
Instruct <= RDSR;
bus_cycle_state := DATA_BYTES;
WHEN "00110101" => -- 35h
Instruct <= RDSR2;
bus_cycle_state := DATA_BYTES;
WHEN "00000001" => -- 01h
Instruct <= WRR;
bus_cycle_state := DATA_BYTES;
WHEN "00000011" => -- 03h
Instruct <= READ;
bus_cycle_state := ADDRESS_BYTES;
WHEN "00001011" => -- 0Bh
Instruct <= FAST_READ;
bus_cycle_state := ADDRESS_BYTES;
WHEN "00111011" => -- 3Bh
Instruct <= FAST_DREAD;
bus_cycle_state := ADDRESS_BYTES;
WHEN "01101011" => -- 6Bh
Instruct <= FAST_QREAD;
IF (QE = '1') THEN
bus_cycle_state := ADDRESS_BYTES;
ELSE
bus_cycle_state := STAND_BY;
END IF;
WHEN "10111011" => -- BBh
Instruct <= FAST_DREAD_2;
bus_cycle_state := ADDRESS_BYTES;
WHEN "11101011" => -- EBh
Instruct <= FAST_QREAD_4;
IF (QE = '1') THEN
bus_cycle_state := ADDRESS_BYTES;
ELSE
bus_cycle_state := STAND_BY;
END IF;
WHEN "11100111" => --E7h
Instruct <= W_QREAD;
IF (QE = '1') THEN
bus_cycle_state := ADDRESS_BYTES;
ELSE
bus_cycle_state := STAND_BY;
END IF;
WHEN "11100011" => -- E3h
Instruct <= WOCT_QREAD;
IF (QE = '1') THEN
bus_cycle_state := ADDRESS_BYTES;
ELSE
bus_cycle_state := STAND_BY;
END IF;
WHEN "01110111" => -- 77h
Instruct <= SET_BURST_WRAP;
IF (QE = '1') THEN
bus_cycle_state := DUMMY_BYTES;
ELSE
bus_cycle_state := STAND_BY;
END IF;
WHEN "11111111" => -- FFh
Instruct <= CONT_RD_RST;
bus_cycle_state := MODE_BYTE;
WHEN "00000010" => -- 02H
Instruct <= PP;
bus_cycle_state := ADDRESS_BYTES;
WHEN "00110010" => -- 32h
Instruct <= QPP;
IF (QE = '1') THEN
bus_cycle_state := ADDRESS_BYTES;
ELSE
bus_cycle_state := STAND_BY;
END IF;
WHEN "00100000" => -- 20h
Instruct <= SE;
bus_cycle_state := ADDRESS_BYTES;
WHEN "01010010" => -- 52h
Instruct <= BE_32;
bus_cycle_state := ADDRESS_BYTES;
WHEN "11011000" => -- D8h
Instruct <= BE_64;
bus_cycle_state := ADDRESS_BYTES;
WHEN "11000111" | "01100000" => -- C7 or 60h
Instruct <= CE;
bus_cycle_state := DATA_BYTES;
WHEN "01110101" => -- 75h
Instruct <= ERS_PG_SUSP;
bus_cycle_state := DATA_BYTES;
WHEN "01111010" => -- 7Ah
Instruct <= ERS_PG_RES;
bus_cycle_state := DATA_BYTES;
WHEN "10111001" => -- B9h
Instruct <= DP;
bus_cycle_state := DATA_BYTES;
WHEN "10101011" => -- ABh
Instruct <= RES_RD_ID;
bus_cycle_state := DUMMY_BYTES;
WHEN "10010000" => -- 90h
Instruct <= RDID;
bus_cycle_state := ADDRESS_BYTES;
WHEN "10010010" => -- 92h
Instruct <= RDID_DUAL;
bus_cycle_state := ADDRESS_BYTES;
WHEN "10010100" => -- 94h
Instruct <= RDID_QUAD;
IF (QE = '1') THEN
bus_cycle_state := ADDRESS_BYTES;
ELSE
bus_cycle_state := STAND_BY;
END IF;
WHEN "01001011" => -- 4Bh
Instruct <= RD_UNIQ_ID;
bus_cycle_state := DUMMY_BYTES;
WHEN "10011111" => -- 9Fh
Instruct <= RDIDJ;
bus_cycle_state := DATA_BYTES;
WHEN "01011010" => -- 5Ah
Instruct <= RD_SFDP;
bus_cycle_state := ADDRESS_BYTES;
WHEN "01000100" => -- 44h
Instruct <= ERS_SCREG;
bus_cycle_state := ADDRESS_BYTES;
WHEN "01000010" => -- 42h
Instruct <= PG_SCREG;
bus_cycle_state := ADDRESS_BYTES;
WHEN "01001000" => -- 48h
Instruct <= RD_SCREG;
bus_cycle_state := ADDRESS_BYTES;
WHEN OTHERS =>
NULL;
END CASE;
END IF;
ELSE
REPORT "Device is in HOLD mode, opcode"
SEVERITY NOTE;
END IF;
WHEN ADDRESS_BYTES =>
IF (HOLDNeg_pullup = '1' AND QE='0') OR QE='1' THEN
IF (Instruct = READ OR Instruct = FAST_READ OR
Instruct = FAST_DREAD OR Instruct = RDID OR
Instruct = SE OR Instruct = PP OR
Instruct = RD_SCREG OR Instruct = PG_SCREG OR
Instruct = RD_SFDP OR Instruct = BE_32 OR
Instruct = BE_64 OR Instruct = ERS_SCREG OR
((Instruct = QPP OR Instruct = FAST_QREAD)
AND QE = '1')) THEN
Address_in(addr_cnt) := SIIn;
addr_cnt := addr_cnt + 1;
IF addr_cnt = 3*BYTE THEN
FOR I IN 23 DOWNTO 0 LOOP
addr_bytes(23-i) := Address_in(i);
END LOOP;
Address <= to_nat(addr_bytes);
change_addr <= '1','0' AFTER 1 ns;
IF (Instruct = PP OR Instruct = QPP
OR Instruct = READ OR Instruct = SE
OR Instruct = BE_32 OR Instruct = BE_64
OR Instruct = RDID OR Instruct = PG_SCREG
OR Instruct = ERS_SCREG) THEN
bus_cycle_state := DATA_BYTES;
ELSE
bus_cycle_state := DUMMY_BYTES;
END IF;
END IF;
ELSIF (Instruct = RDID_DUAL OR
Instruct = FAST_DREAD_2) THEN
IF (SOIn /= 'Z') THEN
Address_in(2*addr_cnt) := SOIn;
Address_in(2*addr_cnt + 1):= SIIn;
read_cnt := 0;
addr_cnt := addr_cnt + 1;
IF (addr_cnt = (3*BYTE)/2) THEN
addr_cnt := 0;
FOR I IN 23 DOWNTO 0 LOOP
addr_bytes(23-i) := Address_in(i);
END LOOP;
Address <= to_nat(addr_bytes);
change_addr <= '1','0' AFTER 1 ns;
bus_cycle_state := MODE_BYTE;
END IF;
ELSIF (mode_bits(5 downto 4) = "10") THEN
opcode_double_in(opcode_cnt) := SIIn;
opcode_cnt := opcode_cnt + 1;
IF (opcode_cnt = 2*BYTE) THEN
FOR I IN 15 DOWNTO 0 LOOP
opcode_double(i) :=
opcode_double_in(15-i);
END LOOP;
IF (opcode_double="1111111111111111") THEN
Instruct <= CONT_RD_RST;
bus_cycle_state := MODE_BYTE;
END IF;
END IF;
END IF;
ELSIF (QE = '1' AND (Instruct = FAST_QREAD_4 OR
Instruct = W_QREAD OR Instruct = WOCT_QREAD OR
Instruct = RDID_QUAD)) THEN
IF (SOIn /= 'Z') THEN
Address_in(4*addr_cnt) := HOLDNegIn;
Address_in(4*addr_cnt+1) := WPNegIn;
Address_in(4*addr_cnt+2) := SOIn;
Address_in(4*addr_cnt+3) := SIIn;
read_cnt := 0;
addr_cnt := addr_cnt + 1;
IF (addr_cnt = (3*BYTE)/4) THEN
addr_cnt := 0;
FOR I IN 23 DOWNTO 0 LOOP
addr_bytes(23-i) := Address_in(i);
END LOOP;
Address <= to_nat(addr_bytes);
change_addr <= '1','0' AFTER 1 ns;
bus_cycle_state := MODE_BYTE;
END IF;
ELSIF (mode_bits(5 downto 4) = "10") THEN
opcode_in(opcode_cnt) := SIIn;
opcode_cnt := opcode_cnt + 1;
IF (opcode_cnt = BYTE) THEN
FOR I IN 7 DOWNTO 0 LOOP
opcode(i) :=
opcode_in(7-i);
END LOOP;
IF (opcode = "11111111") THEN
Instruct <= CONT_RD_RST;
bus_cycle_state := MODE_BYTE;
END IF;
END IF;
END IF;
END IF;
ELSE
REPORT "Device is in HOLD mode, addr"
SEVERITY NOTE;
END IF;
WHEN MODE_BYTE =>
IF (QE = '1' OR (HOLDNeg_pullup = '1' AND QE = '0')) THEN
IF (Instruct = SET_BURST_WRAP AND QE = '1') THEN
wrap_in(4*wrap_cnt) := HOLDNegIn;
wrap_in(4*wrap_cnt+1) := WPNegIn;
wrap_in(4*wrap_cnt+2) := SOIn;
wrap_in(4*wrap_cnt+3) := SIIn;
wrap_cnt := wrap_cnt + 1;
IF (wrap_cnt = BYTE/4) THEN
wrap_cnt := 0;
FOR I IN 7 DOWNTO 0 LOOP
wrap_byte(i) := wrap_in(7-i);
END LOOP;
bus_cycle_state := DATA_BYTES;
END IF;
CASE (wrap_byte(6 DOWNTO 5)) IS
WHEN "00" =>
w_size := 8;
WHEN "01" =>
w_size := 16;
WHEN "10" =>
w_size := 32;
WHEN "11" =>
w_size := 64;
WHEN OTHERS =>
NULL;
END CASE;
ELSIF ((Instruct = FAST_QREAD_4 OR
Instruct = WOCT_QREAD OR Instruct = W_QREAD OR
Instruct = RDID_QUAD ) AND QE = '1') THEN
mode_in(4*mode_cnt) := HOLDNegIn;
mode_in(4*mode_cnt+1) := WPNegIn;
mode_in(4*mode_cnt+2) := SOIn;
mode_in(4*mode_cnt+3) := SIIn;
mode_cnt := mode_cnt + 1;
IF (mode_cnt = BYTE/4) THEN
mode_cnt := 0;
FOR I IN 7 DOWNTO 0 LOOP
mode_bits(i) := mode_in(7-i);
END LOOP;
IF (Instruct = WOCT_QREAD) THEN
bus_cycle_state := DATA_BYTES;
ELSE
bus_cycle_state := DUMMY_BYTES;
END IF;
END IF;
ELSIF (Instruct = RDID_DUAL OR
Instruct = FAST_DREAD_2) THEN
mode_in(2*mode_cnt) := SOIn;
mode_in(2*mode_cnt+1) := SIIn;
mode_cnt := mode_cnt + 1;
IF (mode_cnt = BYTE/2) THEN
mode_cnt := 0;
FOR I IN 7 DOWNTO 0 LOOP
mode_bits(i) := mode_in(7-i);
END LOOP;
bus_cycle_state := DATA_BYTES;
END IF;
END IF;
ELSE
REPORT "Device is in HOLD mode, mode"
SEVERITY NOTE;
END IF;
WHEN DUMMY_BYTES =>
IF (QE = '1' OR (HOLDNeg_pullup = '1' AND QE = '0')) THEN
IF ((Instruct = FAST_QREAD_4 OR
Instruct = RDID_QUAD) AND QE = '1') THEN
dummy_cnt := dummy_cnt + 1;
IF (dummy_cnt = BYTE/2) THEN
bus_cycle_state := DATA_BYTES;
END IF;
ELSIF (Instruct = W_QREAD AND QE = '1') THEN
dummy_cnt := dummy_cnt + 1;
IF (dummy_cnt = BYTE/4) THEN
bus_cycle_state := DATA_BYTES;
END IF;
ELSIF (Instruct = SET_BURST_WRAP AND QE = '1') THEN
dummy_cnt := dummy_cnt + 1;
IF (dummy_cnt = 3*BYTE/4) THEN
bus_cycle_state := MODE_BYTE;
END IF;
ELSIF (Instruct = FAST_QREAD AND QE = '1') THEN
dummy_cnt := dummy_cnt + 1;
IF (dummy_cnt = BYTE) THEN
bus_cycle_state := DATA_BYTES;
END IF;
ELSIF (Instruct=FAST_READ OR Instruct=RD_SFDP
OR Instruct = FAST_DREAD OR Instruct=RD_SCREG) THEN
dummy_cnt := dummy_cnt + 1;
IF (dummy_cnt = BYTE) THEN
bus_cycle_state := DATA_BYTES;
END IF;
ELSIF (Instruct = RD_UNIQ_ID) THEN
dummy_cnt := dummy_cnt + 1;
IF (dummy_cnt = 4*BYTE) THEN
bus_cycle_state := DATA_BYTES;
END IF;
ELSE -- for RES_RD_ID
dummy_cnt := dummy_cnt + 1;
IF (dummy_cnt = 3*BYTE) THEN
bus_cycle_state := DATA_BYTES;
END IF;
END IF;
ELSE
REPORT "Device is in HOLD mode, dummy"
SEVERITY NOTE;
END IF; -- end of DUMMY_BYTES
WHEN DATA_BYTES =>
IF (Instruct = PP OR Instruct = WRR OR
Instruct = PG_SCREG) THEN
IF ((HOLDNeg_pullup = '1' AND QE='0') OR QE='1') THEN
IF (data_cnt > 2047) THEN
--In case of serial mode and PP,IF more than
--256 bytes are sent to the device
IF (bit_cnt = 0) THEN
FOR I IN 0 TO (255*BYTE-1) LOOP
Data_in(i) := Data_in(i+8);
END LOOP;
END IF;
Data_in(2040 + bit_cnt) := SIIn;
bit_cnt := bit_cnt + 1;
IF (bit_cnt = 8) THEN
bit_cnt := 0;
END IF;
data_cnt := data_cnt + 1;
ELSE
Data_in(data_cnt) := SIIn;
data_cnt := data_cnt + 1;
bit_cnt := 0;
END IF;
ELSE
REPORT "Device is in HOLD mode, data"
SEVERITY NOTE;
END IF;
ELSIF (Instruct = QPP AND QE ='1') THEN
pp_quad := TRUE;
quad_nybble := HOLDNegIn & WPNegIn & SOIn & SIIn;
IF (data_cnt > 511) THEN
--In case of quad mode and QPP,IF more than
-- 256 bytes are sent to the device
FOR I IN 0 TO 510 LOOP
quad_data_in(i) := quad_data_in(i+1);
END LOOP;
quad_data_in(511) := to_nat(quad_nybble);
data_cnt := data_cnt +1;
ELSE
IF (quad_nybble /= "ZZZZ") THEN
quad_data_in(data_cnt) :=
to_nat(quad_nybble);
END IF;
data_cnt := data_cnt +1;
END IF;
END IF;
WHEN OTHERS => NULL;
END CASE;
END IF;
END IF;
IF falling_edge(SCK_ipd) AND (bus_cycle_state = DATA_BYTES AND
CSNeg_ipd ='0') THEN
IF (((Instruct = RDSR OR Instruct = RDSR2 OR
Instruct = FAST_READ OR Instruct = FAST_DREAD OR
Instruct = FAST_DREAD_2 OR Instruct = RES_RD_ID OR
Instruct = RDID OR Instruct = RDID_DUAL OR
Instruct = RD_UNIQ_ID OR Instruct = RDIDJ OR
Instruct = RD_SFDP OR Instruct = RD_SCREG OR
Instruct = READ) AND ((HOLDNeg_pullup ='1' AND QE='0') OR QE='1'))
OR ((Instruct = FAST_QREAD OR Instruct = FAST_QREAD_4 OR
Instruct = W_QREAD OR Instruct = RDID_QUAD OR
Instruct = WOCT_QREAD) AND QE='1')) THEN
read_out <= '1', '0' AFTER 1 ns;
END IF;
END IF;
IF rising_edge(CSNeg_ipd) THEN
IF (bus_cycle_state=MODE_BYTE AND Instruct = CONT_RD_RST) THEN
mode_bits(5 downto 4) := "11";
mode_bits(7 downto 6) := "00";
mode_bits(3 downto 0) := "0000";
bus_cycle_state := STAND_BY;
ELSIF (bus_cycle_state=DATA_BYTES AND
NOT (mode_bits(5 downto 4)="10")) THEN
bus_cycle_state := STAND_BY;
CASE (Instruct) IS
WHEN WREN | WRDI | SET_BURST_WRAP | SE | BE_32 | BE_64 |
CE | ERS_PG_RES | DP | ERS_SCREG =>
IF (data_cnt = 0) THEN
write <= '0';
END IF;
WHEN WRENV =>
write <= '0';
wren_vlt_flag := TRUE;
WHEN RES_RD_ID =>
write <= '0';
res_flag := TRUE;
WHEN WRR =>
IF (data_cnt = 8) THEN
--If CS# is driven high after eight
--cycle,only the Status Register is
--written to.
write <= '0';
FOR i IN 0 TO 7 LOOP
Status_reg1_in(i) <= Data_in(7-i);
END LOOP;
ELSIF (data_cnt = 16) THEN
--After the 16th cycle both the
--Status and Configuration Registers
--are written to.
write <= '0';
FOR i IN 0 TO 7 LOOP
Status_reg1_in(i) <= Data_in(7-i);
END LOOP;
FOR j IN 0 TO 7 LOOP
Status_reg2_in(j) <= Data_in(15-j);
END LOOP;
END IF;
WHEN PP | PG_SCREG =>
IF (data_cnt > 0) THEN
IF ((data_cnt mod 8) = 0) THEN
write <= '0';
FOR I IN 0 TO 255 LOOP
FOR J IN 7 DOWNTO 0 LOOP
Byte_slv(j) :=
Data_in((i*8) + (7-j));
END LOOP;
WByte(i) <=
to_nat(Byte_slv);
END LOOP;
IF (data_cnt > 256*BYTE) THEN
Byte_number <= 255;
ELSE
Byte_number <= ((data_cnt/8) - 1);
END IF;
END IF;
END IF;
WHEN QPP =>
IF (data_cnt >0) THEN
IF ((data_cnt mod 2) = 0) THEN
write <= '0';
FOR I IN 0 TO 255 LOOP
FOR J IN 1 DOWNTO 0 LOOP
Quad_slv :=
to_slv(quad_data_in((i*2) +
(1-j)),4);
Byte_slv(4*j+3 DOWNTO 4*j) :=
Quad_slv;
END LOOP;
WByte(i) <= to_nat(Byte_slv);
END LOOP;
IF (data_cnt > 256*BYTE/4) THEN
Byte_number <= 255;
ELSE
Byte_number <= ((data_cnt/2) - 1);
END IF;
END IF;
END IF;
WHEN others =>
null;
END CASE;
ELSIF (bus_cycle_state=DATA_BYTES AND
(mode_bits(5 DOWNTO 4)="10")) THEN
bus_cycle_state := DATA_BYTES;
ELSE
bus_cycle_state := STAND_BY;
IF (HOLDNeg_pullup ='1' AND (Instruct = RES_RD_ID) AND
(dummy_cnt = 0)) THEN
write <= '0';
res_flag := FALSE;
END IF;
END IF;
END IF; -- end of rising_edge_CSNeg_ipd
END PROCESS BusCycleDecode;
---------------------------------------------------------------------------
-- Timing control for the Page Program
---------------------------------------------------------------------------
ProgTime : PROCESS(PSTART, PGSUSP, PGRES)
VARIABLE pob : time;
VARIABLE elapsed : time;
VARIABLE start : time;
VARIABLE duration : time;
BEGIN
IF Instruct = PP OR Instruct = QPP OR Instruct = PG_SCREG THEN
IF LongTimming THEN
pob := tdevice_PP;
ELSE
pob := tdevice_PP / 10;
END IF;
END IF;
IF rising_edge(PSTART) AND PDONE = '1' THEN
elapsed := 0 ns;
PDONE <= '0', '1' AFTER pob;
start := NOW;
ELSIF PGSUSP'EVENT AND PGSUSP = '1' AND PDONE /= '1' THEN
elapsed := NOW - start;
duration := pob - elapsed;
PDONE <= '0';
ELSIF PGRES'EVENT AND PGRES = '1' AND PDONE /= '1'THEN
start := NOW;
PDONE <= '0', '1' AFTER duration;
END IF;
END PROCESS ProgTime;
---------------------------------------------------------------------------
-- Timing control for the Write Status Register
---------------------------------------------------------------------------
WriteTime : PROCESS(WSTART)
VARIABLE wob : time;
BEGIN
IF LongTimming THEN
wob := tdevice_WRR;
ELSE
wob := tdevice_WRR / 100;
END IF;
IF rising_edge(WSTART) AND WDONE = '1' THEN
WDONE <= '0', '1' AFTER wob;
END IF;
END PROCESS WriteTime;
---------------------------------------------------------------------------
-- Timing control for the Write Status Register when Write Enable for
-- Volatile Status Register was issued
---------------------------------------------------------------------------
WriteTimeVlt : PROCESS(VLTSTART)
VARIABLE wvob : time;
BEGIN
wvob := tdevice_VRR;
IF rising_edge(VLTSTART) AND VLTDONE = '1' THEN
VLTDONE <= '0' , '1' AFTER wvob;
END IF;
END PROCESS WriteTimeVlt;
---------------------------------------------------------------------------
-- Timing control for the Erase Operation
---------------------------------------------------------------------------
ErsTime : PROCESS(ESTART, ESUSP, ERES)
VARIABLE seo : time;
VARIABLE beo32 : time;
VARIABLE beo64 : time;
VARIABLE ceo : time;
VARIABLE elapsed : time;
VARIABLE start : time;
VARIABLE duration : time;
BEGIN
IF LongTimming THEN
seo := tdevice_SE;
beo32 := tdevice_BE1;
beo64 := tdevice_BE2;
ceo := tdevice_CE;
ELSE
seo := tdevice_SE / 100;
beo32 := tdevice_BE1 / 100;
beo64 := tdevice_BE2 / 100;
ceo := tdevice_CE / 100;
END IF;
IF rising_edge(ESTART) AND EDONE = '1' THEN
IF Instruct = CE THEN
duration := ceo;
ELSIF Instruct = BE_64 THEN
duration := beo64;
ELSIF Instruct = BE_32 THEN
duration := beo32;
ELSIF Instruct = BE_64 THEN
duration := beo64;
ELSE -- sector erase 4KB, instruct SE
duration := seo;
END IF;
elapsed := 0 ns;
EDONE <= '0', '1' AFTER duration;
start := NOW;
ELSIF ESUSP'EVENT AND ESUSP = '1' AND EDONE /= '1' THEN
elapsed := NOW - start;
duration := duration - elapsed;
EDONE <= '0';
ELSIF ERES'EVENT AND ERES = '1' AND EDONE /= '1' THEN
start := NOW;
EDONE <= '0', '1' AFTER duration;
END IF;
END PROCESS ErsTime;
CheckCEOnPowerUP :PROCESS(CSNeg_ipd)
BEGIN
IF (PoweredUp = '0' AND falling_edge(CSNeg_ipd)) THEN
REPORT InstancePath & partID &
": Device is selected during Power Up"
SEVERITY WARNING;
END IF;
END PROCESS;
---------------------------------------------------------------------------
-- Main Behavior Process
-- combinational process for next state generation
---------------------------------------------------------------------------
StateGen :PROCESS(PoweredUp, write, CSNeg_ipd, WDONE, ERSSUSP_out, RES1_out,
ERSRES_out, PRGSUSP_out, EDONE,PRGRES_out, DP_out, PDONE,
VLTDONE,RES2_out)
BEGIN
IF rising_edge(PoweredUp) THEN
next_state <= IDLE;
ELSE
CASE current_state IS
WHEN IDLE =>
IF falling_edge(write) THEN
IF (Instruct = WRR AND (SRP1='0' AND
(SRP0='0' OR (SRP0='1' AND WPNeg ='1')))) THEN
IF (WEL='1' AND NOT (wren_vlt_flag)) THEN
next_state <= WRITE_SR;
ELSIF (WEL='0' AND wren_vlt_flag) THEN
next_state <= WRITE_SR_V;
END IF;
ELSIF (Instruct = PP AND WEL='1') THEN
sect := Address / 16#1000#;
sect_tmp_pg := sect;
IF (Sec_Prot(sect) = '0') THEN
next_state <= PAGE_PG;
END IF;
ELSIF (Instruct = QPP AND WEL='1' AND QE='1') THEN
sect := Address / 16#1000#;
sect_tmp_pg := sect;
IF (Sec_Prot(sect) = '0') THEN
next_state <= PAGE_PG;
END IF;
ELSIF (Instruct = PG_SCREG AND WEL='1') THEN
sect := Address / 16#1000#;
IF ((sect < 4 AND sect > 0) AND
LB_bits(sect-1)='0') THEN
next_state <= PAGE_PG;
END IF;
ELSIF (Instruct = ERS_SCREG AND WEL='1') THEN
sect := Address / 16#1000#;
IF ((sect <= 3) AND LB_bits(sect-1)='0') THEN
next_state <= SECTOR_ERS;
END IF;
ELSIF ((Instruct = SE OR Instruct = BE_32 OR
Instruct = BE_64) AND WEL='1') THEN
sect := Address / 16#1000#;
sect_tmp_ers := sect;
IF (Sec_Prot(sect) = '0') THEN
next_state <= SECTOR_ERS;
END IF;
ELSIF (Instruct = CE AND WEL='1' AND
((CMP='0' AND BP2='0' AND BP1='0' AND BP0='0') OR
(CMP='1' AND BP2='1' AND BP1='1' AND BP0='1'))) THEN
next_state <= BULK_ERS;
ELSE
next_state <= IDLE;
END IF;
ELSIF rising_edge(DP_out) THEN
next_state <= DP_DOWN;
END IF;
WHEN WRITE_SR =>
IF rising_edge(WDONE) THEN
next_state <= IDLE;
END IF; -- end of WRITE_SR
WHEN WRITE_SR_V =>
IF rising_edge(VLTDONE) THEN
next_state <= IDLE;
END IF;
WHEN PAGE_PG =>
IF (PRGSUSP_out'event AND PRGSUSP_out = '1') THEN
next_state <= PG_SUSP;
ELSIF rising_edge(PDONE) THEN
next_state <= IDLE;
END IF; -- end of PAGE_PG
WHEN PG_SUSP =>
IF (PRGRES_out'event AND PRGRES_out = '1') THEN
next_state <= PAGE_PG;
ELSIF falling_edge(write) THEN
IF (Instruct = SE OR Instruct = BE_32 OR
Instruct = BE_64) THEN
sect := Address / 16#1000#;
IF ((Sec_Prot(sect) = '0') AND
(sect /= sect_tmp_pg)) THEN
next_state <= PG_SUSP_ERS;
END IF;
END IF;
END IF; -- end of PG_SUSP
WHEN PG_SUSP_ERS =>
IF rising_edge(EDONE) THEN
next_state <= PG_SUSP;
ELSE
next_state <= PG_SUSP_ERS;
END IF;
WHEN BULK_ERS =>
IF rising_edge(EDONE) THEN
next_state <= IDLE;
END IF;
WHEN SECTOR_ERS =>
IF (ERSSUSP_out'event AND ERSSUSP_out = '1') THEN
next_state <= ERS_SUSP;
ELSIF rising_edge(EDONE) THEN
next_state <= IDLE;
END IF;
WHEN ERS_SUSP =>
IF (ERSRES_out'event AND ERSRES_out = '1') THEN
next_state <= SECTOR_ERS;
ELSIF falling_edge(write) THEN
IF (Instruct = PP OR (Instruct = QPP AND QE='1')) THEN
sect := Address / 16#1000#;
IF ((Sec_Prot(sect) = '0') AND
(sect /= sect_tmp_ers)) THEN
next_state <= ERS_SUSP_PG;
END IF;
ELSIF (Instruct = PG_SCREG) THEN
sect := Address / 16#1000#;
IF ((sect < 4 AND sect > 0) AND
LB_bits(sect-1)='0') THEN
next_state <= ERS_SUSP_PG;
END IF;
END IF;
END IF;
WHEN ERS_SUSP_PG =>
IF rising_edge(PDONE) THEN
next_state <= ERS_SUSP;
ELSE
next_state <= ERS_SUSP_PG;
END IF;
WHEN DP_DOWN =>
IF rising_edge(RES1_out) OR rising_edge(RES2_out) THEN
next_state <= IDLE;
END IF;
END CASE;
END IF;
END PROCESS StateGen;
---------------------------------------------------------------------------
--FSM Output generation and general funcionality
---------------------------------------------------------------------------
Functional : PROCESS(read_out, Instruct, SCK_ipd, change_addr, write,
Address, PDONE, WDONE, EDONE, ERSSUSP_out, PoweredUp,
CSNeg_ipd, RES1_out, ERSRES_out, PRGSUSP_out,PRGRES_out,
VLTDONE, current_state, DP_out, RES2_out,SUSP_FL_OUT)
VARIABLE WData : WByteType:= (OTHERS => MaxData);
VARIABLE oe : boolean := FALSE;
VARIABLE AddrLo : NATURAL;
VARIABLE AddrHi : NATURAL;
VARIABLE AddrLo_ers : NATURAL;
VARIABLE AddrHi_ers : NATURAL;
VARIABLE AddrLo_wrap : NATURAL;
VARIABLE AddrHi_wrap : NATURAL;
VARIABLE Addr : NATURAL;
VARIABLE Addr_w : NATURAL;
VARIABLE Addr_ers : NATURAL;
VARIABLE Addr_tmp : NATURAL;
VARIABLE Addr_tmp_2 : NATURAL;
VARIABLE Addr_tmp_3 : NATURAL;
VARIABLE Addr_screg : NATURAL;
VARIABLE Addr_screg_tmp : NATURAL;
VARIABLE data_out : std_logic_vector(7 downto 0);
VARIABLE ident_out : std_logic_vector(23 downto 0);
VARIABLE ident_out2 : std_logic_vector(15 downto 0);
VARIABLE uniq_id : std_logic_vector(63 downto 0);
VARIABLE old_bit : std_logic_vector(7 downto 0);
VARIABLE new_bit : std_logic_vector(7 downto 0);
VARIABLE old_int : INTEGER RANGE -1 to MaxData;
VARIABLE new_int : INTEGER RANGE -1 to MaxData;
VARIABLE wr_cnt : NATURAL RANGE 0 TO 255;
VARIABLE cnt : NATURAL RANGE 0 TO 256 := 0;
BEGIN
oe := rising_edge(read_out) AND PoweredUp = '1';
IF Instruct'EVENT THEN
read_cnt := 0;
fast_rd <= true;
dual_read <= false;
slow_read <= false;
quad_read <= false;
sr_read <= false;
read_id <= false;
pp_quad := FALSE;
IF (current_state = IDLE AND DP_in = '1') THEN
REPORT "Command results can be corrupted "
SEVERITY WARNING;
END IF;
END IF;
IF rising_edge(PoweredUp) THEN
WEL := '0';
BUSY := '0';
SUS := '0';
change_prot_bits <= '1', '0' AFTER 1 ns;
END IF;
IF change_addr'EVENT THEN
read_addr := Address;
END IF;
IF RES1_out'EVENT AND RES1_out = '1' THEN
RES1_in <= '0';
END IF;
IF RES2_out'EVENT AND RES2_out = '1' THEN
RES2_in <= '0';
END IF;
IF SUSP_FL_OUT'EVENT AND SUSP_FL_OUT = '1' THEN
SUSP_FL_IN <= '0';
END IF;
CASE current_state IS
WHEN IDLE =>
fast_rd <= true;
dual_read <= false;
slow_read <= false;
quad_read <= false;
read_id <= false;
sr_read <= false;
res_flag := FALSE;
pg_screg_flag <= false;
ers_screg_flag <= false;
IF falling_edge(write) AND DP_in ='0' THEN
read_cnt := 0;
IF (Instruct = WREN) THEN
WEL := '1';
ELSIF (Instruct = WRDI) THEN
WEL := '0';
ELSIF (Instruct = WRR) THEN
IF(SRP1='0' AND (SRP0='0' OR
(SRP0='1' AND WPNeg='1'))) THEN
IF WEL='1' AND NOT (wren_vlt_flag) THEN
WSTART <= '1', '0' AFTER 5 ns;
BUSY := '1';
ELSIF (WEL='0' AND wren_vlt_flag) THEN
VLTSTART <= '1', '0' AFTER 5 ns;
END IF;
ELSE
WEL := '0';
END IF;
ELSIF ((Instruct = PP OR (Instruct = QPP AND QE='1'))
AND WEL='1' AND PDONE='1') THEN
sect := Address / 16#1000#;
IF (Sec_Prot(sect) = '0') THEN
PSTART <= '1', '0' AFTER 5 ns;
PGSUSP <= '0';
PGRES <= '0';
BUSY := '1';
SA <= sect;
Addr := Address;
Addr_tmp:= Address;
wr_cnt := Byte_number;
FOR I IN wr_cnt DOWNTO 0 LOOP
IF Viol /= '0' THEN
WData(i) := -1;
ELSE
WData(i) := WByte(i);
END IF;
END LOOP;
ELSE
WEL := '0';
END IF;
ELSIF (Instruct = PG_SCREG AND WEL='1') THEN
sect := Address / 16#1000#;
IF ((sect <= 3) AND LB_bits(sect-1)='0') THEN
PSTART <= '1', '0' AFTER 5 ns;
PGSUSP <= '0';
PGRES <= '0';
BUSY := '1';
SA <= sect;
wr_cnt := Byte_number;
Addr_screg := Address mod 16#1000#;
Addr_screg_tmp := Address mod 16#1000#;
pg_screg_flag <= true;
FOR I IN wr_cnt DOWNTO 0 LOOP
IF Viol /= '0' THEN
WData(i) := -1;
ELSE
WData(i) := WByte(i);
END IF;
END LOOP;
ELSE
WEL := '0';
END IF;
ELSIF ((Instruct = SE OR Instruct = BE_32 OR
Instruct = BE_64) AND WEL='1') THEN
sect := Address / 16#1000#;
IF (Sec_Prot(sect) = '0') THEN
ESTART <= '1', '0' AFTER 5 ns;
ESUSP <= '0';
ERES <= '0';
BUSY := '1';
Addr_ers := Address;
ELSE
WEL := '0';
END IF;
ELSIF (Instruct = CE AND WEL='1') THEN
IF ((CMP='0' AND BP2='0' AND BP1='0' AND BP0='0') OR
(CMP='1' AND BP2='1' AND BP1='1' AND BP0='1')) THEN
ESTART <= '1', '0' AFTER 5 ns;
ESUSP <= '0';
ERES <= '0';
BUSY := '1';
ELSE
WEL := '0';
END IF;
ELSIF (Instruct = ERS_SCREG AND WEL='1') THEN
sect := Address / 16#1000#;
IF ((sect <= 3) AND LB_bits(sect-1)='0') THEN
ESTART <= '1', '0' AFTER 5 ns;
ESUSP <= '0';
ERES <= '0';
BUSY := '1';
SA <= sect;
ers_screg_flag <= true;
ELSE
WEL := '0';
END IF;
ELSIF (Instruct = DP) THEN
RES2_in <= '0';
RES1_in <= '0';
DP_in <= '1';
END IF;
-- end of falling_edge_write
ELSIF (oe AND DP_in='0') THEN
IF (Instruct = RDSR) THEN
--Read Status Register
sr_read <= true;
SOut_zd <= Status_reg1(7-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
END IF;
ELSIF (Instruct = RDSR2) THEN
sr_read <= true;
SOut_zd <= Status_reg2(7-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
END IF;
ELSIF (Instruct = READ OR Instruct = FAST_READ) THEN
IF (Instruct = READ) THEN
fast_rd <= false;
dual_read <= false;
slow_read <= true;
quad_read <= false;
sr_read <= false;
ELSE
fast_rd <= true;
dual_read <= false;
slow_read <= false;
quad_read <= false;
sr_read <= false;
END IF;
IF (Mem(read_addr) /= -1) THEN
data_out := to_slv(Mem(read_addr),8);
SOut_zd <= data_out(7-read_cnt);
ELSE
SOut_zd <= 'U';
END IF;
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
IF (read_addr = AddrRANGE) THEN
read_addr := 0;
ELSE
read_addr := read_addr + 1;
END IF;
END IF;
ELSIF (Instruct=FAST_DREAD OR Instruct=FAST_DREAD_2) THEN
fast_rd <= false;
dual_read <= true;
slow_read <= false;
quad_read <= false;
sr_read <= false;
data_out := to_slv(Mem(read_addr),8);
SOut_zd <= data_out(7-2*read_cnt);
SIOut_zd <= data_out(6-2*read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 4) THEN
read_cnt := 0;
IF (read_addr = AddrRANGE) THEN
read_addr := 0;
ELSE
read_addr := read_addr + 1;
END IF;
END IF;
ELSIF ((Instruct=FAST_QREAD OR Instruct=FAST_QREAD_4 OR
Instruct=W_QREAD OR Instruct=WOCT_QREAD)
AND QE='1') THEN
IF ((Instruct=W_QREAD AND (Address mod 2 /= 0) ) OR
(Instruct=WOCT_QREAD AND
(Address mod 16 /= 0))) THEN
read_cnt := read_cnt + 1;
IF (read_cnt = 2) THEN
read_cnt := 0;
REPORT "Word Read can't execute Wrong Address"
SEVERITY NOTE;
END IF;
ELSE
fast_rd <= false;
dual_read <= false;
slow_read <= false;
quad_read <= true;
sr_read <= false;
Addr_w := Address;
data_out := to_slv(Mem(read_addr),8);
HOLDNegOut_zd <= data_out(7-4*read_cnt);
WPNegOut_zd <= data_out(6-4*read_cnt);
SOut_zd <= data_out(5-4*read_cnt);
SIOut_zd <= data_out(4-4*read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 2) THEN
read_cnt := 0;
IF (wrap_byte(4)='0' AND (Instruct=FAST_QREAD_4
OR Instruct=W_QREAD)) THEN
ADDRHILO_WRAP(AddrLo_wrap,AddrHi_wrap,
Addr_w,w_size);
IF (read_addr = AddrHi_wrap) THEN
read_addr := AddrLo_wrap;
ELSE
read_addr := read_addr + 1;
END IF;
ELSE
IF (read_addr = AddrRANGE) THEN
read_addr := 0;
ELSE
read_addr := read_addr + 1;
END IF;
END IF;
END IF;
END IF;
ELSIF (Instruct=RDID OR Instruct=RDID_DUAL OR
Instruct=RDID_QUAD) THEN
IF (read_addr mod 2 = 0) THEN
ident_out2 := to_slv(Manuf_ID,8) &
to_slv(Device_ID1,8);
ELSE
ident_out2 := to_slv(Device_ID1,8) &
to_slv(Manuf_ID,8);
END IF;
read_id <= true;
IF (Instruct = RDID) THEN
fast_rd <= true;
dual_read <= false;
slow_read <= false;
quad_read <= false;
sr_read <= false;
SOut_zd <= ident_out2(15-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 16) THEN
read_cnt := 0;
END IF;
ELSIF (Instruct = RDID_DUAL) THEN
fast_rd <= false;
dual_read <= true;
slow_read <= false;
quad_read <= false;
sr_read <= false;
SOut_zd <= ident_out2(15-2*read_cnt);
SIOut_zd <= ident_out2(14-2*read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
END IF;
ELSE -- (Instruct = RDID_QUAD)
fast_rd <= false;
dual_read <= false;
slow_read <= false;
quad_read <= true;
sr_read <= false;
HOLDNegOut_zd <= ident_out2(15-4*read_cnt);
WPNegOut_zd <= ident_out2(14-4*read_cnt);
SOut_zd <= ident_out2(13-4*read_cnt);
SIOut_zd <= ident_out2(12-4*read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 4) THEN
read_cnt := 0;
END IF;
END IF;
ELSIF (Instruct = RD_UNIQ_ID) THEN
-- unique ID number is not in data sheet
read_id <= true;
uniq_id := to_slv(Unique_id_2,32)&
to_slv(Unique_id_1,32);
SOut_zd <= uniq_id(63-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 64) THEN
read_cnt := 0;
END IF;
ELSIF (Instruct = RDIDJ) THEN
read_id <= true;
ident_out := to_slv(Manuf_ID,8) &
to_slv(Device_ID2,8) & to_slv(Device_ID3,8);
SOut_zd <= ident_out(23-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 24) THEN
read_cnt := 0;
END IF;
ELSIF (Instruct = RD_SFDP) THEN
IF (read_addr / 16#100# = 0) THEN
Addr_tmp_2 := (read_addr mod 16#100#);
data_out := to_slv(SFDP_array(Addr_tmp_2),8);
SOut_zd <= data_out(7-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
IF (read_addr = SFDP_HiAddr) THEN
read_addr := 0;
ELSE
read_addr := read_addr + 1;
END IF;
END IF;
ELSE
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
REPORT "Given SFDP address is out of range"
SEVERITY NOTE;
END IF;
END IF;
ELSIF (Instruct = RD_SCREG) THEN
Addr_tmp_2 := read_addr / 16#100#;
Addr_tmp_3 := read_addr mod 16#100#;
IF (Addr_tmp_2 = 16) THEN
-- Security Register No.1
data_out := to_slv(Security_Reg1(Addr_tmp_3),8);
SOut_zd <= data_out(7-read_cnt);
read_cnt := read_cnt + 1;
ELSIF (Addr_tmp_2 = 32) THEN
-- Security Register No.2
data_out := to_slv(Security_Reg2(Addr_tmp_3),8);
SOut_zd <= data_out(7-read_cnt);
read_cnt := read_cnt + 1;
ELSIF (Addr_tmp_2 = 48) THEN
-- Security Register No.2
data_out := to_slv(Security_Reg3(Addr_tmp_3),8);
SOut_zd <= data_out(7-read_cnt);
read_cnt := read_cnt + 1;
ELSE
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
REPORT "Security Reg address is out of range "
SEVERITY NOTE;
END IF;
END IF;
IF (read_cnt = 8) THEN
read_cnt := 0;
IF (read_addr mod 256 = SecReg_HiAddr) THEN
read_addr := (read_addr/256)*(SecReg_HiAddr+1);
ELSE
read_addr := read_addr + 1;
END IF;
END IF;
ELSIF Instruct = RES_RD_ID THEN
read_id <= true;
data_out := to_slv(Device_ID1,8);
SOut_zd <= data_out(7-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
END IF;
END IF; -- end of oe
ELSIF rising_edge(DP_out) THEN
DP_in <= '0';
END IF; -- end of IDLE state
WHEN WRITE_SR =>
IF (WDONE ='1') THEN
BUSY := '0';
WEL := '0';
SRP0 := Status_reg1_in(7);
SEC := Status_reg1_in(6);
TB := Status_reg1_in(5);
BP2 := Status_reg1_in(4);
BP1 := Status_reg1_in(3);
BP0 := Status_reg1_in(2);
BP_bits := BP2 & BP1 & BP0;
CMP := Status_reg2_in(6);
QE := Status_reg2_in(1);
-- SRP1 bit will only change value from '0' to '1'
-- if SRP1 is '1' than Status Register is protected
--and is not possible to write it
SRP1 := Status_reg2_in(0);
IF LB3 = '0' THEN
LB3 := Status_reg2_in(5);
ELSE
REPORT "LB bit is set to '1', no change allowed"
SEVERITY NOTE;
END IF;
IF LB2 = '0' THEN
LB2 := Status_reg2_in(4);
ELSE
REPORT "LB bit is set to '1', no change allowed"
SEVERITY NOTE;
END IF;
IF LB1 = '0' THEN
LB1 := Status_reg2_in(3);
ELSE
REPORT "LB bit is set to '1', no change allowed"
SEVERITY NOTE;
END IF;
LB_bits := LB3 & LB2 & LB1;
change_prot_bits <= '1' , '0' AFTER 2 ns;
END IF; -- end of WDONE
IF (oe AND Instruct = RDSR) THEN
--Read Status Register 1
sr_read <= true;
SOut_zd <= Status_reg1(7-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
END IF;
END IF; -- end of WRITE_SR
WHEN WRITE_SR_V =>
IF (VLTDONE = '1') THEN
SRP0 := Status_reg1_in(7);
SEC := Status_reg1_in(6);
TB := Status_reg1_in(5);
BP2 := Status_reg1_in(4);
BP1 := Status_reg1_in(3);
BP0 := Status_reg1_in(2);
BP_bits := BP2 & BP1 & BP0;
CMP := Status_reg2_in(6);
QE := Status_reg2_in(1);
-- SRP1 bit will only change value from '0' to '1'
-- if SRP1 is '1' than Status Register is protected
--and is not possible to write it
SRP1 := Status_reg2_in(0);
IF LB3 = '0' THEN
LB3 := Status_reg2_in(5);
ELSIF LB2 = '0' THEN
LB2 := Status_reg2_in(4);
ELSIF LB1 = '0' THEN
LB1 := Status_reg2_in(3);
ELSE
REPORT "LB bit is set to '1', no change allowed"
SEVERITY NOTE;
END IF;
change_prot_bits <= '1' , '0' AFTER 2 ns;
wren_vlt_flag := FALSE;
END IF;
WHEN PAGE_PG | ERS_SUSP_PG =>
IF current_state'event AND PDONE = '0' THEN
IF (Instruct /= PG_SCREG) THEN
ADDRHILO_PG(AddrLo, AddrHi, Addr);
END IF;
cnt := 0;
FOR i IN 0 TO wr_cnt LOOP
new_int := WData(i);
IF (Instruct = PG_SCREG) THEN
IF (sect = 1) THEN
old_int := Security_Reg1(Addr_screg + i - cnt);
ELSIF (sect = 2) THEN
old_int := Security_Reg2(Addr_screg + i - cnt);
ELSE
old_int := Security_Reg3(Addr_screg + i - cnt);
END IF;
ELSE
old_int := Mem(Addr + i - cnt);
END IF;
IF (new_int > -1) THEN
new_bit := to_slv(new_int,8);
IF (old_int > -1) THEN
old_bit := to_slv(old_int,8);
FOR j IN 0 TO 7 LOOP
IF old_bit(j) = '0' THEN
new_bit(j) := '0';
END IF;
END LOOP;
new_int := to_nat(new_bit);
END IF;
WData(i) := new_int;
ELSE
WData(i) := -1;
END IF;
IF (Instruct = PG_SCREG) THEN
IF (sect = 1) THEN
Security_Reg1(Addr_screg + i - cnt) := - 1;
ELSIF (sect = 2) THEN
Security_Reg2(Addr_screg + i - cnt) := - 1;
ELSE
Security_Reg3(Addr_screg + i - cnt) := - 1;
END IF;
ELSE
Mem(Addr + i - cnt) := - 1;
END IF;
IF (Instruct /= PG_SCREG) THEN
IF ((Addr + i) = AddrHi) THEN
Addr := AddrLo;
cnt := i + 1;
END IF;
ELSE
IF Addr_screg + i = SecReg_HiAddr THEN
Addr_screg := SecReg_LoAddr;
cnt := i + 1;
END IF;
END IF;
END LOOP;
cnt := 0;
END IF;
IF (PDONE = '1') THEN
IF (current_state /= ERS_SUSP_PG) THEN
BUSY := '0';
END IF;
WEL := '0';
FOR I IN 0 TO wr_cnt LOOP
IF pg_screg_flag THEN
IF (sect = 1) THEN
Security_Reg1(Addr_screg_tmp + i - cnt) :=WData(i);
ELSIF (sect = 2) THEN
Security_Reg2(Addr_screg_tmp + i - cnt) :=WData(i);
ELSE
Security_Reg3(Addr_screg_tmp + i - cnt) :=WData(i);
END IF;
IF ((Addr_screg_tmp + i) = SecReg_HiAddr) THEN
Addr_screg_tmp := SecReg_LoAddr;
cnt := i + 1;
END IF;
ELSE
Mem(Addr_tmp + i - cnt) := WData(i);
IF ((Addr_tmp + i) = AddrHi) THEN
Addr_tmp := AddrLo;
cnt := i + 1;
END IF;
END IF;
END LOOP;
END IF; -- end of PDONE
IF (Instruct = ERS_PG_SUSP AND current_state = PAGE_PG AND
SUSP_FL_IN = '0') THEN
PGSUSP <= '1', '0' AFTER 1 ns;
PRGSUSP_in <= '1';
END IF;
IF (oe AND Instruct = RDSR) THEN
--Read Status Register 1
sr_read <= true;
SOut_zd <= Status_reg1(7-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
END IF;
END IF;
WHEN PG_SUSP =>
fast_rd <= true;
dual_read <= false;
slow_read <= false;
quad_read <= false;
sr_read <= false;
BUSY := '0';
IF (PRGSUSP_out = '1' AND (Instruct /= ERS_PG_RES)) THEN
PRGSUSP_in <= '0';
--The BUSY bit in the Status Register will indicate that
--the device is ready for another operation.
-- BUSY := '0';
--The SuspEND (SUS) bit in the Status Register2 will
--be set to the logical “1” state to indicate that the
--program operation has been suspENDed.
SUS := '1';
END IF;
IF (PRGRES_out'event AND PRGRES_out = '1') THEN
PRGRES_in <= '0';
BUSY := '1';
END IF;
IF (SUS = '1') THEN
IF falling_edge(write) THEN
IF (Instruct = ERS_PG_RES) THEN
SUS := '0';
PRGRES_in <= '1';
SUSP_FL_IN <= '1';
PGRES <= '1', '0' AFTER 5 ns;
ELSIF ((Instruct = SE OR Instruct = BE_32 OR
Instruct = BE_64) AND WEL='1') THEN
sect := Address / 16#1000#;
IF (sect /= sect_tmp_pg AND
Sec_Prot(sect) = '0') THEN
ESTART <= '1', '0' AFTER 5 ns;
ESUSP <= '0';
ERES <= '0';
BUSY := '1';
Addr_ers := Address;
ELSE
BUSY := '0';
REPORT "Can't erase sector,protected or susp."
SEVERITY NOTE;
END IF;
END IF;
ELSIF (oe) THEN
IF (Instruct = RDSR) THEN
--Read Status Register 1
sr_read <= true;
SOut_zd <= Status_reg1(7-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
END IF;
ELSIF (Instruct = RDSR2) THEN
--Read Status Register 2
sr_read <= true;
SOut_zd <= Status_reg2(7-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
END IF;
ELSIF (Instruct = READ OR Instruct = FAST_READ) THEN
IF (sect_tmp_pg /= read_addr / 16#1000#) THEN
IF (Instruct = READ) THEN
fast_rd <= false;
dual_read <= false;
slow_read <= true;
quad_read <= false;
sr_read <= false;
ELSE
fast_rd <= true;
dual_read <= false;
slow_read <= false;
quad_read <= false;
sr_read <= false;
END IF;
IF (Mem(read_addr) /= -1) THEN
data_out := to_slv(Mem(read_addr),8);
SOut_zd <= data_out(7-read_cnt);
ELSE
SOut_zd <= 'U';
END IF;
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
IF (read_addr = AddrRANGE) THEN
read_addr := 0;
ELSE
read_addr := read_addr + 1;
END IF;
END IF;
ELSE
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
REPORT "Can't read suspended sector"
SEVERITY NOTE;
read_cnt := 0;
END IF;
END IF;
ELSIF (Instruct=FAST_DREAD OR
Instruct=FAST_DREAD_2) THEN
IF sect_tmp_pg /= (read_addr / 16#1000#) THEN
fast_rd <= false;
dual_read <= true;
slow_read <= false;
quad_read <= false;
sr_read <= false;
IF (Mem(read_addr) /= -1) THEN
data_out := to_slv(Mem(read_addr),8);
SOut_zd <= data_out(7-2*read_cnt);
SIOut_zd <= data_out(6-2*read_cnt);
ELSE
SOut_zd <= 'U';
SIOut_zd <= 'U';
END if;
read_cnt := read_cnt + 1;
IF (read_cnt = 4) THEN
read_cnt := 0;
IF (read_addr = AddrRANGE) THEN
read_addr := 0;
ELSE
read_addr := read_addr + 1;
END IF;
END IF;
ELSE
read_cnt := read_cnt + 1;
IF (read_cnt = 4) THEN
REPORT "Can't read suspended sector"
SEVERITY NOTE;
read_cnt := 0;
END IF;
END IF;
ELSIF ((Instruct=FAST_QREAD OR Instruct=W_QREAD
OR Instruct=FAST_QREAD_4 OR Instruct=WOCT_QREAD)
AND QE = '1') THEN
IF sect_tmp_pg /= (read_addr / 16#1000#) THEN
IF ((Instruct=W_QREAD AND
Address mod 2 /= 0) OR
(Instruct=WOCT_QREAD AND
Address mod 16 /= 0)) THEN
read_cnt := read_cnt + 1;
IF (read_cnt = 2) THEN
read_cnt := 0;
REPORT "Word Read - Wrong Read Address"
SEVERITY NOTE;
END IF;
ELSE
fast_rd <= false;
dual_read <= false;
slow_read <= false;
quad_read <= true;
sr_read <= false;
Addr_w := Address;
data_out := to_slv(Mem(read_addr),8);
HOLDNegOut_zd <= data_out(7-4*read_cnt);
WPNegOut_zd <= data_out(6-4*read_cnt);
SOut_zd <= data_out(5-4*read_cnt);
SIOut_zd <= data_out(4-4*read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 2) THEN
read_cnt := 0;
IF (wrap_byte(4)= '0' AND
(Instruct=FAST_QREAD_4 OR
Instruct=W_QREAD)) THEN
ADDRHILO_WRAP(AddrLo_wrap,
AddrHi_wrap, Addr_w,w_size);
IF (read_addr = AddrHi_wrap) THEN
read_addr := AddrLo_wrap;
ELSE
read_addr := read_addr + 1;
END IF;
ELSE
IF (read_addr = AddrRANGE) THEN
read_addr := 0;
ELSE
read_addr := read_addr + 1;
END IF;
END IF;
END IF;
END IF;
ELSE
read_cnt := read_cnt + 1;
IF (read_cnt = 2) THEN
REPORT "Can't read suspended sector"
SEVERITY NOTE;
read_cnt := 0;
END IF;
END IF;
ELSIF (Instruct=RDID OR Instruct=RDID_DUAL OR
Instruct=RDID_QUAD) THEN
IF (read_addr mod 2 = 0) THEN
ident_out2 := to_slv(Manuf_ID,8) &
to_slv(Device_ID1,8);
ELSE
ident_out2 := to_slv(Device_ID1,8)&
to_slv(Manuf_ID,8);
END IF;
read_id <= true;
IF (Instruct = RDID) THEN
fast_rd <= true;
dual_read <= false;
slow_read <= false;
quad_read <= false;
sr_read <= false;
SOut_zd <= ident_out2(15-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 16) THEN
read_cnt := 0;
END IF;
ELSIF (Instruct = RDID_DUAL) THEN
fast_rd <= false;
dual_read <= true;
slow_read <= false;
quad_read <= false;
sr_read <= false;
SOut_zd <= ident_out2(15-2*read_cnt);
SIOut_zd <= ident_out2(14-2*read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
END IF;
ELSE -- (Instruct = RDID_QUAD)
fast_rd <= false;
dual_read <= false;
slow_read <= false;
quad_read <= true;
sr_read <= false;
HOLDNegOut_zd <= ident_out2(15-4*read_cnt);
WPNegOut_zd <= ident_out2(14-4*read_cnt);
SOut_zd <= ident_out2(13-4*read_cnt);
SIOut_zd <= ident_out2(12-4*read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 4) THEN
read_cnt := 0;
END IF;
END IF;
ELSIF (Instruct = RD_UNIQ_ID) THEN
-- unique ID number is not in data sheet
read_id <= true;
uniq_id := to_slv(Unique_id_2,32)&
to_slv(Unique_id_1,32);
SOut_zd <= uniq_id(63-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 64) THEN
read_cnt := 0;
END IF;
ELSIF (Instruct = RDIDJ) THEN
read_id <= true;
ident_out := to_slv(Manuf_ID,8) &
to_slv(Device_ID2,8) & to_slv(Device_ID3,8);
SOut_zd <= ident_out(23-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 24) THEN
read_cnt := 0;
END IF;
ELSIF (Instruct = RD_SFDP) THEN
IF (read_addr / 16#100# = 0) THEN
Addr_tmp_2 := (read_addr mod 16#100#);
data_out := to_slv(SFDP_array(Addr_tmp_2),8);
SOut_zd <= data_out(7-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
IF (read_addr = SFDP_HiAddr) THEN
read_addr := 0;
ELSE
read_addr := read_addr + 1;
END IF;
END IF;
ELSE
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
REPORT "SFDP address is out of range"
SEVERITY NOTE;
END IF;
END IF;
ELSIF (Instruct = RD_SCREG) THEN
Addr_tmp_2 := read_addr / 16#100#;
Addr_tmp_3 := read_addr mod 16#100#;
IF (Addr_tmp_2 = 16) THEN
-- Security Register No.1
data_out := to_slv(Security_Reg1(Addr_tmp_3),8);
SOut_zd <= data_out(7-read_cnt);
read_cnt := read_cnt + 1;
ELSIF (Addr_tmp_2 = 32) THEN
-- Security Register No.2
data_out := to_slv(Security_Reg2(Addr_tmp_3),8);
SOut_zd <= data_out(7-read_cnt);
read_cnt := read_cnt + 1;
ELSIF (Addr_tmp_2 = 48) THEN
-- Security Register No.2
data_out := to_slv(Security_Reg3(Addr_tmp_3),8);
SOut_zd <= data_out(7-read_cnt);
read_cnt := read_cnt + 1;
ELSE
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
REPORT "Security Reg addr is out of range "
SEVERITY NOTE;
END if;
END IF;
IF (read_cnt = 8) THEN
read_cnt := 0;
IF (read_addr mod 256) = SecReg_HiAddr THEN
read_addr:=(read_addr/256)*
(SecReg_HiAddr+1);
ELSE
read_addr := read_addr + 1;
END IF;
END IF;
END IF;
END IF;
END IF;
WHEN SECTOR_ERS | PG_SUSP_ERS =>
IF (current_state'event AND EDONE = '0') THEN
IF (Instruct = SE) THEN
ADDRHILO_SEC4(AddrLo_ers, AddrHi_ers, Addr_ers);
ELSIF (Instruct = BE_32) THEN
ADDRHILO_SEC32(AddrLo_ers, AddrHi_ers, Addr_ers);
ELSIF (Instruct = BE_64) THEN
ADDRHILO_SEC64(AddrLo_ers, AddrHi_ers, Addr_ers);
END IF;
IF (Instruct /= ERS_SCREG) THEN
FOR I IN AddrLo_ers TO AddrHi_ers LOOP
Mem(i) := -1;
END LOOP;
ELSE
IF (sect = 1) THEN
FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP
Security_Reg1(i) := -1;
END LOOP;
ELSIF (sect = 2) THEN
FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP
Security_Reg2(i) := -1;
END LOOP;
ELSE
FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP
Security_Reg3(i) := -1;
END LOOP;
END IF;
END IF;
END IF;
IF (EDONE = '1') THEN
IF (current_state /= PG_SUSP_ERS) THEN
BUSY := '0';
END IF;
WEL := '0';
IF (ers_screg_flag) THEN
IF (sect = 1) THEN
FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP
Security_Reg1(i) := MaxData;
END LOOP;
ELSIF (sect = 2) THEN
FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP
Security_Reg2(i) := MaxData;
END LOOP;
ELSE
FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP
Security_Reg3(i) := MaxData;
END LOOP;
END IF;
ELSE
FOR I IN AddrLo_ers TO AddrHi_ers LOOP
Mem(i) := MaxData;
END LOOP;
END IF;
END IF;
IF (Instruct = ERS_PG_SUSP AND current_state = SECTOR_ERS AND
SUSP_FL_IN = '0') THEN
ESUSP <= '1', '0' AFTER 1 ns;
ERSSUSP_in <= '1';
END IF;
IF (oe AND Instruct = RDSR) THEN
--Read Status Register 1
sr_read <= true;
SOut_zd <= Status_reg1(7-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
END IF;
END IF;
WHEN BULK_ERS =>
IF (current_state'event AND EDONE = '0') THEN
FOR I IN 0 TO AddrRANGE LOOP
Mem(i) := -1;
END LOOP;
END IF;
IF (EDONE = '1') THEN
BUSY := '0';
WEL := '0';
FOR I IN 0 TO AddrRANGE LOOP
Mem(i) := MaxData;
END LOOP;
END IF;
IF (oe AND Instruct = RDSR) THEN
--Read Status Register 1
sr_read <= true;
SOut_zd <= Status_reg1(7-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
END IF;
END IF;
WHEN ERS_SUSP =>
fast_rd <= true;
dual_read <= false;
slow_read <= false;
quad_read <= false;
sr_read <= false;
pg_screg_flag <= false;
BUSY := '0';
IF (ERSSUSP_out = '1' AND (Instruct /= ERS_PG_RES)) THEN
ERSSUSP_in <= '0';
--The BUSY bit in the Status Register will indicate that
--the device is ready for another operation.
-- BUSY := '0';
--The SuspEND (SUS) bit in the Status Register2 will
--be set to the logical “1” state to indicate that the
--program operation has been suspENDed.
SUS := '1';
END IF;
IF (ERSRES_out'event AND ERSRES_out = '1') THEN
ERSRES_in <= '0';
BUSY := '1';
END IF;
IF (SUS = '1') THEN
IF falling_edge(write) THEN
IF (Instruct = ERS_PG_RES) THEN
SUS := '0';
ERSRES_in <= '1';
SUSP_FL_IN <= '1';
ERES <= '1', '0' AFTER 5 ns;
ELSIF ((Instruct = PP OR (Instruct=QPP AND QE='1'))
AND WEL ='1') THEN
sect := Address / 16#1000#;
IF (sect /= sect_tmp_ers AND
Sec_Prot(sect)='0') THEN
PSTART <= '1', '0' AFTER 5 ns;
PGSUSP <= '0';
PGRES <= '0';
BUSY := '1';
SA <= sect;
Addr := Address;
Addr_tmp:= Address;
wr_cnt := Byte_number;
FOR I IN wr_cnt DOWNTO 0 LOOP
IF Viol /= '0' THEN
WData(i) := -1;
ELSE
WData(i) := WByte(i);
END IF;
END LOOP;
ELSE
BUSY := '0';
REPORT "Can't program sector,protected or susp"
SEVERITY NOTE;
END IF;
ELSIF (Instruct = PG_SCREG) THEN
sect := Address / 16#1000#;
IF ((sect <= 3 AND sect >=1) AND
LB_bits(sect-1)='0') THEN
PSTART <= '1', '0' AFTER 5 ns;
PGSUSP <= '0';
PGRES <= '0';
BUSY := '1';
SA <= sect;
wr_cnt := Byte_number;
Addr_screg := Address mod 16#1000#;
Addr_screg_tmp := Address mod 16#1000#;
pg_screg_flag <= true;
FOR I IN wr_cnt DOWNTO 0 LOOP
IF Viol /= '0' THEN
WData(i) := -1;
ELSE
WData(i) := WByte(i);
END IF;
END LOOP;
ELSE
WEL := '0';
END IF;
END IF;
ELSIF (oe) THEN
IF (Instruct = RDSR) THEN
--Read Status Register 1
sr_read <= true;
SOut_zd <= Status_reg1(7-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
END IF;
ELSIF (Instruct = RDSR2) THEN
--Read Status Register 2
sr_read <= true;
SOut_zd <= Status_reg2(7-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
END IF;
ELSIF (Instruct = READ OR Instruct = FAST_READ) THEN
IF sect /= (read_addr / 16#1000#) THEN
IF (Instruct = READ) THEN
fast_rd <= false;
dual_read <= false;
slow_read <= true;
quad_read <= false;
sr_read <= true;
ELSE
fast_rd <= true;
dual_read <= false;
slow_read <= false;
quad_read <= false;
sr_read <= false;
END IF;
IF (Mem(read_addr) /= -1) THEN
data_out := to_slv(Mem(read_addr),8);
SOut_zd <= data_out(7-read_cnt);
ELSE
SOut_zd <= 'U';
END IF;
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
IF (read_addr = AddrRANGE) THEN
read_addr := 0;
ELSE
read_addr := read_addr + 1;
END IF;
END IF;
ELSE
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
REPORT "Can't read suspended sector"
SEVERITY NOTE;
read_cnt := 0;
END IF;
END IF;
ELSIF (Instruct = FAST_DREAD OR
Instruct = FAST_DREAD_2) THEN
IF sect_tmp_ers /= (read_addr / 16#1000#) THEN
fast_rd <= false;
dual_read <= true;
slow_read <= false;
quad_read <= false;
sr_read <= false;
IF (Mem(read_addr) /= -1) THEN
data_out := to_slv(Mem(read_addr),8);
SOut_zd <= data_out(7-2*read_cnt);
SIOut_zd <= data_out(6-2*read_cnt);
ELSE
SOut_zd <= 'U';
SIOut_zd <= 'U';
END IF;
read_cnt := read_cnt + 1;
IF (read_cnt = 4) THEN
read_cnt := 0;
IF (read_addr = AddrRANGE) THEN
read_addr := 0;
ELSE
read_addr := read_addr + 1;
END IF;
END IF;
ELSE
read_cnt := read_cnt + 1;
IF (read_cnt = 4) THEN
REPORT "Can't read suspended sector"
SEVERITY NOTE;
read_cnt := 0;
END IF;
END IF;
ELSIF ((Instruct=FAST_QREAD OR Instruct=W_QREAD
OR Instruct=FAST_QREAD_4 OR Instruct=WOCT_QREAD)
AND QE = '1') THEN
IF sect_tmp_ers /= (read_addr / 16#1000#) THEN
IF ((Instruct=W_QREAD AND
Address mod 2 /= 0) OR
(Instruct=WOCT_QREAD AND
Address mod 16 /=0)) THEN
read_cnt := read_cnt + 1;
IF (read_cnt = 2) THEN
read_cnt := 0;
REPORT "Bad Word Read- Wrong Address"
SEVERITY NOTE;
END IF;
ELSE
fast_rd <= false;
dual_read <= false;
slow_read <= false;
quad_read <= true;
sr_read <= false;
data_out := to_slv(Mem(read_addr),8);
Addr_w := Address;
HOLDNegOut_zd <= data_out(7-4*read_cnt);
WPNegOut_zd <= data_out(6-4*read_cnt);
SOut_zd <= data_out(5-4*read_cnt);
SIOut_zd <= data_out(4-4*read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 2) THEN
read_cnt := 0;
IF (wrap_byte(4)='0' AND
(Instruct=FAST_QREAD_4
OR Instruct=W_QREAD)) THEN
ADDRHILO_WRAP(AddrLo_wrap,
AddrHi_wrap,Addr_w,w_size);
IF (read_addr = AddrHi_wrap) THEN
read_addr := AddrLo_wrap;
ELSE
read_addr := read_addr + 1;
END IF;
ELSE
IF (read_addr = AddrRANGE) THEN
read_addr := 0;
ELSE
read_addr := read_addr + 1;
END IF;
END IF;
END IF;
END IF;
ELSE
read_cnt := read_cnt + 1;
IF (read_cnt = 2) THEN
REPORT "Can't read suspended sector"
SEVERITY NOTE;
read_cnt := 0;
END IF;
END IF;
ELSIF (Instruct=RDID OR Instruct=RDID_DUAL OR
Instruct=RDID_QUAD) THEN
IF (read_addr mod 2 = 0) THEN
ident_out2 := to_slv(Manuf_ID,8) &
to_slv(Device_ID1,8);
ELSE
ident_out2 := to_slv(Device_ID1,8) &
to_slv(Manuf_ID,8);
END IF;
read_id <= true;
IF (Instruct = RDID) THEN
fast_rd <= true;
dual_read <= false;
slow_read <= false;
quad_read <= false;
sr_read <= false;
SOut_zd <= ident_out2(15-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 16) THEN
read_cnt := 0;
END IF;
ELSIF (Instruct = RDID_DUAL) THEN
fast_rd <= false;
dual_read <= true;
slow_read <= false;
quad_read <= false;
sr_read <= false;
SOut_zd <= ident_out2(15-2*read_cnt);
SIOut_zd <= ident_out2(14-2*read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
END IF;
ELSE -- (Instruct = RDID_QUAD)
fast_rd <= false;
dual_read <= false;
slow_read <= false;
quad_read <= true;
sr_read <= false;
HOLDNegOut_zd <= ident_out2(15-4*read_cnt);
WPNegOut_zd <= ident_out2(14-4*read_cnt);
SOut_zd <= ident_out2(13-4*read_cnt);
SIOut_zd <= ident_out2(12-4*read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 4) THEN
read_cnt := 0;
END IF;
END IF;
ELSIF (Instruct = RD_UNIQ_ID) THEN
-- unique ID number is not in data sheet
read_id <= true;
uniq_id := to_slv(Unique_id_2,32)&
to_slv(Unique_id_1,32);
SOut_zd <= uniq_id(63-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 64) THEN
read_cnt := 0;
END IF;
ELSIF (Instruct = RDIDJ) THEN
read_id <= true;
ident_out := to_slv(Manuf_ID,8) &
to_slv(Device_ID2,8) & to_slv(Device_ID3,8);
SOut_zd <= ident_out(23-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 24) THEN
read_cnt := 0;
END IF;
ELSIF (Instruct = RD_SFDP) THEN
IF (read_addr / 16#100# = 0) THEN
Addr_tmp_2 := (read_addr mod 16#100#);
data_out := to_slv(SFDP_array(Addr_tmp_2),8);
SOut_zd <= data_out(7-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
IF (read_addr = SFDP_HiAddr) THEN
read_addr := 0;
ELSE
read_addr := read_addr + 1;
END IF;
END IF;
ELSE
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
REPORT "Given SFDP address is out of range"
SEVERITY NOTE;
END IF;
END IF;
ELSIF (Instruct = RD_SCREG) THEN
Addr_tmp_2 := read_addr / 16#100#;
Addr_tmp_3 := read_addr mod 16#100#;
IF (Addr_tmp_2 = 16) THEN
-- Security Register No.1
data_out :=to_slv(Security_Reg1(Addr_tmp_3),8);
SOut_zd <= data_out(7-read_cnt);
read_cnt := read_cnt + 1;
ELSIF (Addr_tmp_2 = 32) THEN
-- Security Register No.2
data_out :=to_slv(Security_Reg2(Addr_tmp_3),8);
SOut_zd <= data_out(7-read_cnt);
read_cnt := read_cnt + 1;
ELSIF (Addr_tmp_2 = 48) THEN
-- Security Register No.2
data_out :=to_slv(Security_Reg3(Addr_tmp_3),8);
SOut_zd <= data_out(7-read_cnt);
read_cnt := read_cnt + 1;
-- END IF;
ELSE
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
REPORT "Security Reg addr is out of range"
SEVERITY NOTE;
END IF;
END IF;
IF (read_cnt = 8) THEN
read_cnt := 0;
IF (read_addr mod 256 = SecReg_HiAddr) THEN
read_addr := (read_addr/256)*
(SecReg_HiAddr+1);
ELSE
read_addr := read_addr + 1;
END IF;
END IF;
END IF;
END IF;
END IF;
WHEN DP_DOWN =>
IF (oe AND Instruct = RES_RD_ID) THEN
read_id <= true;
data_out := to_slv(Device_ID1,8);
SOut_zd <= data_out(7-read_cnt);
read_cnt := read_cnt + 1;
IF (read_cnt = 8) THEN
read_cnt := 0;
END IF;
END IF;
IF falling_edge(write) THEN
IF (Instruct = RES_RD_ID) THEN
IF res_flag = true THEN
RES2_in <= '1';
ELSE
RES1_in <= '1';
END IF;
ELSE
REPORT "Device is in DPD Mode No instructions allowed"
SEVERITY NOTE;
END IF;
END IF;
END CASE;
--Output Disable Control
IF (CSNeg_ipd = '1') THEN
SIOut_zd <= 'Z';
HOLDNegOut_zd <= 'Z';
WPNegOut_zd <= 'Z';
SOut_zd <= 'Z';
END IF;
END PROCESS Functional;
---------------------------------------------------------------------------
-- SFDP Process
---------------------------------------------------------------------------
SFDPPreload: PROCESS
BEGIN
-----------------------------------------------------------------------
--SFDP array data
-----------------------------------------------------------------------
SFDP_array(16#00#) := 16#53#;
SFDP_array(16#01#) := 16#46#;
SFDP_array(16#02#) := 16#44#;
SFDP_array(16#03#) := 16#50#;
SFDP_array(16#04#) := 16#01#;
SFDP_array(16#05#) := 16#01#;
SFDP_array(16#06#) := 16#00#;
SFDP_array(16#07#) := 16#FF#;
SFDP_array(16#08#) := 16#EF#;
SFDP_array(16#09#) := 16#00#;
SFDP_array(16#0A#) := 16#01#;
SFDP_array(16#0B#) := 16#04#;
SFDP_array(16#0C#) := 16#80#;
SFDP_array(16#0D#) := 16#00#;
SFDP_array(16#0E#) := 16#00#;
SFDP_array(16#0F#) := 16#FF#;
SFDP_array(16#10#) := 16#EF#;
SFDP_array(16#11#) := 16#00#;
SFDP_array(16#12#) := 16#01#;
SFDP_array(16#13#) := 16#00#;
SFDP_array(16#14#) := 16#90#;
SFDP_array(16#15#) := 16#00#;
SFDP_array(16#16#) := 16#00#;
SFDP_array(16#17#) := 16#FF#;
FOR I IN 24 TO 127 LOOP
SFDP_array(i) := MaxData;
END LOOP;
SFDP_array(16#80#) := 16#E5#;
SFDP_array(16#81#) := 16#20#;
SFDP_array(16#82#) := 16#F1#;
SFDP_array(16#83#) := 16#FF#;
SFDP_array(16#84#) := 16#FF#;
SFDP_array(16#85#) := 16#FF#;
SFDP_array(16#86#) := 16#FF#;
SFDP_array(16#87#) := 16#07#;
SFDP_array(16#88#) := 16#44#;
SFDP_array(16#89#) := 16#EB#;
SFDP_array(16#8A#) := 16#08#;
SFDP_array(16#8B#) := 16#6B#;
SFDP_array(16#8C#) := 16#08#;
SFDP_array(16#8D#) := 16#3B#;
SFDP_array(16#8E#) := 16#80#;
SFDP_array(16#8F#) := 16#BB#;
FOR I IN 144 TO 255 LOOP
SFDP_array(i) := MaxData;
END LOOP;
WAIT;
END PROCESS SFDPPreload;
---------------------------------------------------------------------------
-- Sector Protection Bits
---------------------------------------------------------------------------
Protect : PROCESS(change_prot_bits)
BEGIN
IF rising_edge(change_prot_bits) THEN
CASE BP_bits IS
WHEN "000" =>
IF (CMP = '0') THEN
Sec_Prot := (others => '0');
ELSE
Sec_Prot := (others => '1');
END IF;
WHEN "001" =>
IF (CMP = '0') THEN
IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
Sec_Prot(4095 downto 4032) :=
(others => '1');
Sec_Prot(4031 downto 0) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
Sec_Prot(63 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 64) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
Sec_Prot(4095) := '1';
Sec_Prot(4094 downto 0) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
Sec_Prot(0) := '1';
Sec_Prot(4095 downto 1) :=
(others => '0');
END IF;
ELSE
IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
Sec_Prot(4031 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 4032) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
Sec_Prot(4095 downto 64) :=
(others => '1');
Sec_Prot(63 downto 0) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
Sec_Prot(4094 downto 0) :=
(others => '1');
Sec_Prot(4095) := '0';
ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
Sec_Prot(4095 downto 1) :=
(others => '1');
Sec_Prot(0) := '0';
END IF;
END IF;
WHEN "010" =>
IF (CMP = '0') THEN
IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
Sec_Prot(4095 downto 3968) :=
(others => '1');
Sec_Prot(3967 downto 0) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
Sec_Prot(127 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 128) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
Sec_Prot(4095 downto 4094) :=
(others => '1');
Sec_Prot(4093 downto 0) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
Sec_Prot(1 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 2) :=
(others => '0');
END IF;
ELSE
IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
Sec_Prot(3967 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 3968) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
Sec_Prot(4095 downto 128) :=
(others => '1');
Sec_Prot(127 downto 0) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
Sec_Prot(4093 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 4094) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
Sec_Prot(4095 downto 2) :=
(others => '1');
Sec_Prot(1 downto 0) :=
(others => '0');
END IF;
END IF;
WHEN "011" =>
IF (CMP = '0') THEN
IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
Sec_Prot(4095 downto 3840) :=
(others => '1');
Sec_Prot(3839 downto 0) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
Sec_Prot(255 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 256) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
Sec_Prot(4095 downto 4092) :=
(others => '1');
Sec_Prot(4091 downto 0) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
Sec_Prot(3 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 4) :=
(others => '0');
END IF;
ELSE
IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
Sec_Prot(3839 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 3840) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
Sec_Prot(4095 downto 256) :=
(others => '1');
Sec_Prot(255 downto 0) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
Sec_Prot(4091 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 4092) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
Sec_Prot(4095 downto 4) :=
(others => '1');
Sec_Prot(3 downto 0) :=
(others => '0');
END IF;
END IF;
WHEN "100" =>
IF (CMP = '0') THEN
IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
Sec_Prot(4095 downto 3584) :=
(others => '1');
Sec_Prot(3583 downto 0) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
Sec_Prot(511 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 512) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
Sec_Prot(4095 downto 4088) :=
(others => '1');
Sec_Prot(4087 downto 0) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
Sec_Prot(7 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 8) :=
(others => '0');
END IF;
ELSE
IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
Sec_Prot(3583 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 3584) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
Sec_Prot(4095 downto 512) :=
(others => '1');
Sec_Prot(511 downto 0) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
Sec_Prot(4087 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 4088) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
Sec_Prot(4095 downto 8) :=
(others => '1');
Sec_Prot(7 downto 0) :=
(others => '0');
END IF;
END IF;
WHEN "101" =>
IF (CMP = '0') THEN
IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
Sec_Prot(4095 downto 3072) :=
(others => '1');
Sec_Prot(3071 downto 0) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
Sec_Prot(1023 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 1024) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
Sec_Prot(4095 downto 4088) :=
(others => '1');
Sec_Prot(4087 downto 0) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
Sec_Prot(7 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 8) :=
(others => '0');
END IF;
ELSE
IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
Sec_Prot(3071 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 3072) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
Sec_Prot(4095 downto 1024) :=
(others => '1');
Sec_Prot(1023 downto 0) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
Sec_Prot(4087 downto 0) :=
(others => '1');
Sec_Prot(4095 downto 4088) :=
(others => '0');
ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
Sec_Prot(4095 downto 8) :=
(others => '1');
Sec_Prot(7 downto 0) :=
(others => '0');
END IF;
END IF;
WHEN "110" =>
IF (CMP = '0') THEN
IF (SEC = '0' AND TB = '0') THEN
Sec_Prot(4095 downto 2048) := (others => '1');
Sec_Prot(2047 downto 0) := (others => '0');
ELSIF (SEC = '0' AND TB = '1') THEN
Sec_Prot(2047 downto 0) := (others => '1');
Sec_Prot(4095 downto 2048) := (others => '0');
END IF;
ELSE
IF (SEC = '0' AND TB = '0') THEN
Sec_Prot(4095 downto 2048) := (others => '0');
Sec_Prot(2047 downto 0) := (others => '1');
ELSIF (SEC = '0' AND TB = '1') THEN
Sec_Prot(4095 downto 2048) := (others => '1');
Sec_Prot(2047 downto 0) := (others => '0');
END IF;
END IF;
WHEN "111" =>
IF (CMP = '0') THEN
Sec_Prot(4095 downto 0) := (others => '1');
ELSE
Sec_Prot(4095 downto 0) := (others => '0');
END IF;
WHEN OTHERS =>
Sec_Prot := (OTHERS => '1');
END CASE; -- end of CASE BP_bits
END IF;
END PROCESS Protect;
HOLD_FRAME_ON_PO_ZD : PROCESS(SOut_zd, SIOut_zd, HOLDNegIn)
BEGIN
IF (HOLDNegIn = '0' AND QE /= '1') THEN
hold_mode := TRUE;
SIOut_z <= 'Z';
SOut_z <= 'Z';
ELSE
IF hold_mode THEN
SIOut_z <= SIOut_zd AFTER tpd_HOLDNeg_SO(trz0);
SOut_z <= SOut_zd AFTER tpd_HOLDNeg_SO(trz0);
hold_mode := FALSE;
ELSE
SIOut_z <= SIOut_zd;
SOut_z <= SOut_zd;
hold_mode := FALSE;
END IF;
END IF;
END PROCESS HOLD_FRAME_ON_PO_ZD;
HOLD_PULL_UP : PROCESS(HOLDNegIn)
BEGIN
IF (QE = '0') THEN
IF (HOLDNegIn = 'Z') THEN
HOLDNeg_pullup <= '1';
ELSE
HOLDNeg_pullup <= HOLDNegIn;
END IF;
END IF;
END PROCESS HOLD_PULL_UP;
WP_PULL_UP : PROCESS(WPNegIn)
BEGIN
IF (QE = '0') THEN
IF (WPNegIn = 'Z') THEN
WPNeg_pullup <= '1';
ELSE
WPNeg_pullup <= WPNegIn;
END IF;
END IF;
END PROCESS WP_PULL_UP;
---------------------------------------------------------------------------
---- File Read Section - Preload Control
---------------------------------------------------------------------------
MemPreload: PROCESS
-- text file input variables
FILE mem_file : text is mem_file_name;
FILE screg_file : text is screg_file_name;
VARIABLE ind : NATURAL RANGE 0 TO AddrRANGE:= 0;
VARIABLE screg_ind: NATURAL RANGE 16#00# TO 16#2FF#:= 16#00#;
VARIABLE buf : line;
BEGIN
-- memory preload
IF (mem_file_name (1 to 4)/= "none" AND UserPreload) THEN
ind := 0;
Mem := (OTHERS => MaxData);
WHILE (not ENDFILE (mem_file)) LOOP
READLINE (mem_file, buf);
IF buf(1) = '/' THEN
NEXT;
ELSIF buf(1) = '@' THEN
ind := h(buf(2 to 7)); --address
ELSE
IF ind <= AddrRANGE THEN
Mem(ind) := h(buf(1 to 2));
END IF;
IF ind < AddrRANGE THEN
ind := ind + 1;
END IF;
END IF;
END LOOP;
END IF;
-----------------------------------------------------------------------
-- Security Register Preload
-----------------------------------------------------------------------
IF (screg_file_name(1 to 4) /= "none" AND UserPreload) THEN
ind := 0;
Security_Reg1 := (OTHERS => MaxData);
Security_Reg2 := (OTHERS => MaxData);
Security_Reg3 := (OTHERS => MaxData);
WHILE (not ENDFILE (screg_file)) LOOP
READLINE (screg_file, buf);
IF buf(1) = '/' THEN
NEXT;
ELSIF buf(1) = '@' THEN
screg_ind := h(buf(2 to 4)); --address
ELSE
IF screg_ind <= 16#0FF# THEN
Security_Reg1(screg_ind) := h(buf(1 to 2));
ELSIF screg_ind>=16#100# AND screg_ind<=16#1FF# THEN
Security_Reg2(screg_ind-16#100#) := h(buf(1 to 2));
ELSIF screg_ind>=16#200# AND screg_ind<=16#2FF# THEN
Security_Reg3(screg_ind-16#200#) := h(buf(1 to 2));
END IF;
IF (screg_ind mod 16#100#) < 16#FF# THEN
screg_ind := screg_ind + 1;
END IF;
END IF;
END LOOP;
END IF;
WAIT;
END PROCESS MemPreload;
---------------------------------------------------------------------------
-- Path Delay Section
---------------------------------------------------------------------------
S_Out_PathDelay_Gen : PROCESS(SOut_z)
VARIABLE SO_GlitchData : VitalGlitchDataType;
BEGIN
VitalPathDelay01Z (
OutSignal => SOut,
OutSignalName => "SO",
OutTemp => SOut_z,
Mode => VitalTransport,
GlitchData => SO_GlitchData,
Paths => (
0 => (InputChangeTime => SCK_ipd'LAST_EVENT,
PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_0),
PathCondition => SOut_z /= 'Z' AND NOT(read_id)),
1 => (InputChangeTime => SCK_ipd'LAST_EVENT,
PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_1),
PathCondition => SOut_z /= 'Z' AND read_id),
2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT,
PathDelay => tpd_CSNeg_SO,
PathCondition => CSNeg_ipd = '1'),
3 => (InputChangeTime => HOLDNegIn'LAST_EVENT,
PathDelay => tpd_HOLDNeg_SO,
PathCondition => QE = '0')
)
);
END PROCESS;
SI_Out_PathDelay : PROCESS(SIOut_z)
VARIABLE SI_GlitchData : VitalGlitchDataType;
BEGIN
VitalPathDelay01Z (
OutSignal => SIOut,
OutSignalName => "SI",
OutTemp => SIOut_z,
Mode => VitalTransport,
GlitchData => SI_GlitchData,
Paths => (
0 => (InputChangeTime => SCK_ipd'LAST_EVENT,
PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_0),
PathCondition => SIOut_z /= 'Z' AND NOT(read_id)),
1 => (InputChangeTime => SCK_ipd'LAST_EVENT,
PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_1),
PathCondition => SIOut_z /= 'Z' AND read_id),
2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT,
PathDelay => tpd_CSNeg_SO,
PathCondition => CSNeg_ipd = '1' AND SIOut_zd = 'Z'),
3 => (InputChangeTime => HOLDNegIn'LAST_EVENT,
PathDelay => tpd_HOLDNeg_SO,
PathCondition => SIOut_z /= 'Z' AND QE = '0')
)
);
END PROCESS;
HOLD_Out_PathDelay : PROCESS(HOLDNegOut_zd)
VARIABLE HOLD_GlitchData : VitalGlitchDataType;
BEGIN
VitalPathDelay01Z (
OutSignal => HOLDNegOut,
OutSignalName => "HOLDNeg",
OutTemp => HOLDNegOut_zd,
GlitchData => HOLD_GlitchData,
Paths => (
0 => (InputChangeTime => SCK_ipd'LAST_EVENT,
PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_0),
PathCondition => HOLDNegOut_zd /= 'Z' --AND quad_read
AND QE = '1' AND NOT(read_id)),
1 => (InputChangeTime => SCK_ipd'LAST_EVENT,
PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_1),
PathCondition => HOLDNegOut_zd /= 'Z' --AND quad_read
AND QE = '1' AND read_id),
2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT,
PathDelay => tpd_CSNeg_SO,
PathCondition => CSNeg_ipd = '1' AND --quad_read AND
HOLDNegOut_zd = 'Z' AND QE = '1')
)
);
END PROCESS;
WP_Out_PathDelay : PROCESS(WPNegOut_zd)
VARIABLE WP_GlitchData : VitalGlitchDataType;
BEGIN
VitalPathDelay01Z (
OutSignal => WPNegOut,
OutSignalName => "WPNeg",
OutTemp => WPNegOut_zd,
GlitchData => WP_GlitchData,
Paths => (
0 => (InputChangeTime => SCK_ipd'LAST_EVENT,
PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_0),
PathCondition => WPNegOut_zd /= 'Z' --AND quad_read
AND QE = '1' AND NOT(read_id)),
1 => (InputChangeTime => SCK_ipd'LAST_EVENT,
PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_1),
PathCondition => WPNegOut_zd /= 'Z' -- AND quad_read
AND QE = '1' AND read_id),
2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT,
PathDelay => tpd_CSNeg_SO,
PathCondition => CSNeg_ipd = '1' AND --quad_read AND
WPNegOut_zd = 'Z' AND QE = '1')
)
);
END PROCESS;
END BLOCK behavior;
END vhdl_behavioral;