git-svn-id: http://moon:8086/svn/vhdl/trunk@1291 cc03376c-175c-47c8-b038-4cd826a8556b
2533 lines
110 KiB
VHDL
2533 lines
110 KiB
VHDL
-------------------------------------------------------------------------------
|
|
-- File Name: s25fl032p.vhd
|
|
-------------------------------------------------------------------------------
|
|
-- Copyright (C) 2011 Spansion, LLC.
|
|
--
|
|
-- MODIFICATION HISTORY:
|
|
--
|
|
-- version: | author: | mod date: | changes made:
|
|
-- V1.0 D.Stanojkovic 08 Jan 22 Inital Release
|
|
-- V1.1 D.Stanojkovic 08 Feb 20 BP bits setting corrected
|
|
-- V1.2 D.Stanojkovic 08 Mar 05 MPM mode corrected
|
|
-- V1.3 D.Stanojkovic 08 Mar 20 MPM mode removed
|
|
-- V1.4 J.Stoickov 08 Sep 16 Latest datasheet aligned
|
|
-- V1.5 J.Stoickov 08 Dec 10 Latest datasheet aligned
|
|
-- (S25FL129 064 032P)
|
|
-- Program Error bit will not be
|
|
-- set after programming in
|
|
-- protect memory region
|
|
-- V1.6 V.Mancev 10 Sep 29 Implementation of internal pull-up
|
|
-- for HOLDNeg and WPNeg pins
|
|
-- V1.7 V.Mancev 11 Dec 15 Latest datasheet aligned
|
|
-- (S25FL032P_00_05)
|
|
----------------------------------------------------------------------------
|
|
---
|
|
-- PART DESCRIPTION:
|
|
--
|
|
-- Library: FLASH
|
|
-- Technology: FLASH MEMORY
|
|
-- Part: S25FL032P
|
|
--
|
|
-- Description: 32 Megabit Serial Flash Memory with 104 MHz SPI Bus Interface
|
|
--
|
|
-------------------------------------------------------------------------------
|
|
-- 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 s25fl032p IS
|
|
GENERIC (
|
|
-- tipd delays: interconnect path delays
|
|
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
|
|
tpd_SCK_SO : VitalDelayType01Z := UnitDelay01Z; -- tV
|
|
tpd_SCK_SI : VitalDelayType01Z := UnitDelay01Z; -- tV
|
|
tpd_CSNeg_SO : VitalDelayType01Z := UnitDelay01Z; -- tDIS
|
|
tpd_HOLDNeg_SO : VitalDelayType01Z := UnitDelay01Z; -- tLZ,tHZ
|
|
|
|
--tsetup values
|
|
tsetup_CSNeg_SCK : VitalDelayType := UnitDelay; -- tCSS /
|
|
tsetup_HOLDNeg_SCK : VitalDelayType := UnitDelay; -- tHC /
|
|
tsetup_SI_SCK : VitalDelayType := UnitDelay; -- tsuDAT /
|
|
tsetup_WPNeg_CSNeg : VitalDelayType := UnitDelay; -- tWPS \
|
|
|
|
--thold values
|
|
thold_CSNeg_SCK : VitalDelayType := UnitDelay; -- tCSH /
|
|
thold_HOLDNeg_SCK : VitalDelayType := UnitDelay; -- tCHHH /
|
|
thold_SI_SCK : VitalDelayType := UnitDelay; -- thdDAT /
|
|
thold_WPNeg_CSNeg : VitalDelayType := UnitDelay; -- tWPH \
|
|
|
|
--tpw values: pulse width
|
|
tpw_SCK_serial_fast_posedge : VitalDelayType := UnitDelay; -- tWH
|
|
tpw_SCK_serial_posedge : VitalDelayType := UnitDelay; -- tWH
|
|
tpw_SCK_dual_posedge : VitalDelayType := UnitDelay; -- tWH
|
|
tpw_SCK_rd_jid_posedge : VitalDelayType := UnitDelay; -- tWH
|
|
tpw_SCK_serial_fast_negedge : VitalDelayType := UnitDelay; -- tWL
|
|
tpw_SCK_serial_negedge : VitalDelayType := UnitDelay; -- tWL
|
|
tpw_SCK_dual_negedge : VitalDelayType := UnitDelay; -- tWL
|
|
tpw_SCK_rd_jid_negedge : VitalDelayType := UnitDelay; -- tWL
|
|
tpw_CSNeg_read_posedge : VitalDelayType := UnitDelay; -- tCS
|
|
tpw_CSNeg_pgm_posedge : VitalDelayType := UnitDelay; -- tCS
|
|
|
|
-- tperiod min (calculated as 1/max freq)
|
|
tperiod_SCK_serial_rd : VitalDelayType := UnitDelay;--fSCK=40MHz
|
|
tperiod_SCK_serial_fast_rd : VitalDelayType := UnitDelay;--fSCK=104MHz
|
|
tperiod_SCK_dual_fast_rd : VitalDelayType := UnitDelay;--fSCK=80MHz
|
|
tperiod_SCK_serial_rd_jid : VitalDelayType := UnitDelay;--fSCK=50MHz
|
|
|
|
-- tdevice values: values for internal delays
|
|
-- Page Program Operation
|
|
tdevice_PP : VitalDelayType := 3 ms;
|
|
-- Page Program Operation (ACC=9V))
|
|
tdevice_EP : VitalDelayType := 2.4 ms; --tPP
|
|
-- Sector Erase Operation
|
|
tdevice_SE : VitalDelayType := 2 sec; --tSE
|
|
-- Bulk Erase Operation
|
|
tdevice_BE : VitalDelayType := 64 sec; --tBE
|
|
-- Write Status Register Operation
|
|
tdevice_WR : VitalDelayType := 50 ms; --tW
|
|
-- Deep Power Down
|
|
tdevice_DP : VitalDelayType := 10 us; --tDP
|
|
-- Release from Software Protect Mode
|
|
tdevice_RES : VitalDelayType := 30 us; --tRES
|
|
-- Parameter block erase
|
|
tdevice_PE : VitalDelayType := 800 ms; --tPE
|
|
-- VCC (min) to CS# Low
|
|
tdevice_PU : VitalDelayType := 300 us; --tPU
|
|
-- generic control parameters
|
|
InstancePath : STRING := DefaultInstancePath;
|
|
TimingChecksOn : BOOLEAN := DefaultTimingChecks;
|
|
MsgOn : BOOLEAN := DefaultMsgOn;
|
|
XOn : BOOLEAN := DefaultXon;
|
|
-- memory file to be loaded
|
|
mem_file_name : STRING := "s25fl032p.mem";
|
|
otp_file_name : STRING := "s25fl032pOTP.mem";
|
|
|
|
UserPreload : BOOLEAN := FALSE; --TRUE;
|
|
LongTimming : BOOLEAN := TRUE;
|
|
|
|
-- For FMF SDF technology file usage
|
|
TimingModel : STRING := DefaultTimingModel
|
|
);
|
|
PORT (
|
|
SCK : IN std_ulogic := 'U'; -- serial clock input
|
|
SI : INOUT std_ulogic := 'U'; -- serial data input
|
|
CSNeg : IN std_ulogic := 'U'; -- chip select input
|
|
HOLDNeg : INOUT std_ulogic := 'U'; -- hold input
|
|
WPNeg : INOUT std_ulogic := 'U'; -- write protect input
|
|
SO : INOUT std_ulogic := 'U' -- SO
|
|
);
|
|
ATTRIBUTE VITAL_LEVEL0 of s25fl032p : ENTITY IS TRUE;
|
|
END s25fl032p;
|
|
|
|
-------------------------------------------------------------------------------
|
|
-- ARCHITECTURE DECLARATION
|
|
-------------------------------------------------------------------------------
|
|
ARCHITECTURE vhdl_behavioral of s25fl032p IS
|
|
ATTRIBUTE VITAL_LEVEL0 OF vhdl_behavioral : ARCHITECTURE IS TRUE;
|
|
|
|
CONSTANT PartID : STRING := "s25fl032p";
|
|
CONSTANT MaxData : NATURAL := 16#FF#; --255;
|
|
CONSTANT SecSize : NATURAL := 16#FFFF#; --65535
|
|
CONSTANT SecSize_4 : NATURAL := 16#FFF#; --4095
|
|
CONSTANT SecSize_8 : NATURAL := 16#1FFF#; --8191
|
|
CONSTANT OTPSize : NATURAL := 511;
|
|
CONSTANT OTPLoAddr : NATURAL := 16#100#;
|
|
CONSTANT OTPHiAddr : NATURAL := 16#2FF#;
|
|
CONSTANT SecNum : NATURAL := 63;
|
|
CONSTANT PageNum : NATURAL := 16#3FFF#;
|
|
CONSTANT HiAddrBit : NATURAL := 23;
|
|
CONSTANT AddrRANGE : NATURAL := 16#3FFFFF#;
|
|
CONSTANT BYTE : NATURAL := 8;
|
|
--Manufacturer Identification
|
|
CONSTANT Manuf_ID : NATURAL := 16#01#;
|
|
--Electronic Signature
|
|
CONSTANT ES : NATURAL := 16#15#;
|
|
--Device ID
|
|
--Manufacturer Identification && Memory Type && Memory Capacity
|
|
CONSTANT Jedec_ID : NATURAL := 16#20#; -- first byte of Device ID
|
|
CONSTANT DeviceID : NATURAL := 16#0215#;
|
|
CONSTANT ExtendedBytes : NATURAL := 16#4D#;
|
|
CONSTANT ReservedBytes : NATURAL := 16#00#;
|
|
|
|
-- interconnect path delay signals
|
|
SIGNAL SCK_ipd : std_ulogic := 'U';
|
|
SIGNAL SI_ipd : std_ulogic := 'U';
|
|
SIGNAL SO_ipd : std_ulogic := 'U';
|
|
SIGNAL CSNeg_ipd : std_ulogic := 'U';
|
|
SIGNAL HOLDNeg_ipd : std_ulogic := 'U';
|
|
SIGNAL WPNeg_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 PU_in : std_ulogic := '0';
|
|
SIGNAL PU_out : std_ulogic := '0';
|
|
SIGNAL SE_in : std_ulogic := '0';
|
|
SIGNAL SE_out : std_ulogic := '0';
|
|
SIGNAL BE_in : std_ulogic := '0';
|
|
SIGNAL BE_out : std_ulogic := '0';
|
|
SIGNAL EP_in : std_ulogic := '0';
|
|
SIGNAL EP_out : std_ulogic := '0';
|
|
SIGNAL WR_in : std_ulogic := '0';
|
|
SIGNAL WR_out : std_ulogic := '0';
|
|
SIGNAL DP_in : std_ulogic := '0';
|
|
SIGNAL DP_out : std_ulogic := '0';
|
|
SIGNAL PE_in : std_ulogic := '0';
|
|
SIGNAL PE_out : std_ulogic := '0';
|
|
SIGNAL RES_in : std_ulogic := '0';
|
|
SIGNAL RES_out : std_ulogic := '0';
|
|
|
|
BEGIN
|
|
---------------------------------------------------------------------------
|
|
-- Internal Delays
|
|
---------------------------------------------------------------------------
|
|
-- Artificial VITAL primitives to incorporate internal delays
|
|
PP :VitalBuf(PP_out, PP_in, (tdevice_PP ,UnitDelay));
|
|
PU :VitalBuf(PU_out, PU_in, (tdevice_PU ,UnitDelay));
|
|
SE :VitalBuf(SE_out, SE_in, (tdevice_SE ,UnitDelay));
|
|
BE :VitalBuf(BE_out, BE_in, (tdevice_BE ,UnitDelay));
|
|
EP :VitalBuf(EP_out, EP_in, (tdevice_EP ,UnitDelay));
|
|
WR :VitalBuf(WR_out, WR_in, (tdevice_WR ,UnitDelay));
|
|
DP :VitalBuf(DP_out, DP_in, (tdevice_DP ,UnitDelay));
|
|
PE :VitalBuf(PE_out, PE_in, (tdevice_PE ,UnitDelay));
|
|
RES :VitalBuf(RES_out, RES_in, (tdevice_RES ,UnitDelay));
|
|
|
|
---------------------------------------------------------------------------
|
|
-- Wire Delays
|
|
---------------------------------------------------------------------------
|
|
WireDelay : BLOCK
|
|
BEGIN
|
|
|
|
w_1 : VitalWireDelay (SCK_ipd, SCK, tipd_SCK);
|
|
w_2 : VitalWireDelay (SI_ipd, SI, tipd_SI);
|
|
w_3 : VitalWireDelay (SO_ipd, SO, tipd_SO);
|
|
|
|
w_4: VitalWireDelay (CSNeg_ipd, CSNeg, tipd_CSNeg);
|
|
w_5: VitalWireDelay (HOLDNeg_ipd, HOLDNeg, tipd_HOLDNeg);
|
|
w_6: VitalWireDelay (WPNeg_ipd, WPNeg, tipd_WPNeg);
|
|
|
|
END BLOCK;
|
|
|
|
---------------------------------------------------------------------------
|
|
-- Main Behavior Block
|
|
---------------------------------------------------------------------------
|
|
Behavior: BLOCK
|
|
|
|
PORT (
|
|
SCK : IN std_ulogic := 'U';
|
|
SIIn : IN std_ulogic := 'U';
|
|
SIOut : OUT std_ulogic := 'U';
|
|
SOIn : IN std_logic := 'U';
|
|
SOut : OUT std_logic := '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 (
|
|
SCK => SCK_ipd,
|
|
SIIn => SI_ipd,
|
|
|
|
SOIn => SO_ipd,
|
|
|
|
SOut => SO,
|
|
|
|
CSNeg => CSNeg_ipd,
|
|
|
|
HOLDNegIn => HOLDNeg_ipd,
|
|
WPNegIn => WPNeg_ipd,
|
|
|
|
SIOut => SI,
|
|
WPNegOut => WPNeg,
|
|
HOLDNegOut => HOLDNeg
|
|
);
|
|
|
|
-- State Machine : State_Type
|
|
TYPE state_type IS (IDLE,
|
|
WRITE_SR,
|
|
PAGE_PG,
|
|
OTP_PG,
|
|
SECTOR_ER,
|
|
BULK_ER,
|
|
P4_ER,
|
|
P8_ER,
|
|
DP_DOWN_WAIT,
|
|
DP_DOWN
|
|
);
|
|
|
|
-- Instruction Type
|
|
TYPE instruction_type IS (NONE,
|
|
WREN,
|
|
WRDI,
|
|
WRR,
|
|
RDSR,
|
|
READ,
|
|
READ_ID,
|
|
RDID,
|
|
FAST_READ,
|
|
DUAL_READ,
|
|
QUAD_READ,
|
|
DH_READ,
|
|
QH_READ,
|
|
SE,
|
|
BE,
|
|
PP,
|
|
QPP,
|
|
DP,
|
|
RES_READ_ES,
|
|
ENTER_PRL,
|
|
EXIT_PRL,
|
|
CLSR,
|
|
RCR,
|
|
P4E,
|
|
P8E,
|
|
OTPR,
|
|
OTPP
|
|
);
|
|
|
|
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;
|
|
--OTP Memory Array
|
|
TYPE OTPArr IS ARRAY (OTPLoAddr TO OTPHiAddr) OF INTEGER
|
|
RANGE -1 TO MaxData;
|
|
|
|
---------------------------------------------------------------------------
|
|
-- memory declaration
|
|
---------------------------------------------------------------------------
|
|
SHARED VARIABLE Mem : MemArray := (OTHERS => MaxData);
|
|
-- OTP Sector
|
|
SHARED VARIABLE OTPMem : OTPArr := (OTHERS => MaxData);
|
|
|
|
SIGNAL WByte : WByteType := (OTHERS => 0);
|
|
SIGNAL WOTPByte : INTEGER RANGE -1 TO 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';
|
|
|
|
SHARED VARIABLE Status_reg : std_logic_vector(7 downto 0)
|
|
:= (others => '0');
|
|
|
|
SIGNAL Status_reg_in : std_logic_vector(7 downto 0)
|
|
:= (others => '0');
|
|
|
|
-- Status register Write In Progress Bit
|
|
ALIAS WIP :std_logic IS Status_reg(0);
|
|
-- Status register Write Enable Latch Bit
|
|
ALIAS WEL :std_logic IS Status_reg(1);
|
|
-- Status register block protect Bits
|
|
ALIAS BP0 :std_logic IS Status_reg(2);
|
|
ALIAS BP1 :std_logic IS Status_reg(3);
|
|
ALIAS BP2 :std_logic IS Status_reg(4);
|
|
-- status register Erase Error bit
|
|
ALIAS E_ERR :std_logic IS Status_reg(5);
|
|
-- status register Program Error bit
|
|
ALIAS P_ERR :std_logic IS Status_reg(6);
|
|
-- status register write disable
|
|
ALIAS SRWD :std_logic IS Status_reg(7);
|
|
|
|
SHARED VARIABLE Sec_conf_reg : std_logic_vector(7 downto 0)
|
|
:= (others => '0');
|
|
|
|
SIGNAL Sec_conf_reg_in : std_logic_vector(7 downto 0)
|
|
:= (others => '0');
|
|
|
|
-- Configuration Register FREEZE bit
|
|
ALIAS FREEZE :std_logic IS Sec_conf_reg(0);
|
|
-- Configuration Register QUAD bit
|
|
ALIAS QUAD :std_logic IS Sec_conf_reg(1);
|
|
-- Configuration Register TBPARM bit
|
|
ALIAS TBPARM :std_logic IS Sec_conf_reg(2);
|
|
-- Configuration Register BPNV bit
|
|
ALIAS BPNV :std_logic IS Sec_conf_reg(3);
|
|
-- Security Configuration Register the TBPROT bit
|
|
ALIAS TBPROT :std_logic IS Sec_conf_reg(5);
|
|
|
|
-- The Lock Protection Registers for OTP Memory space
|
|
SHARED VARIABLE PR_LOCK1 :std_logic_vector(15 downto 0);
|
|
SHARED VARIABLE PR_LOCK2 :std_logic_vector(15 downto 0);
|
|
SHARED VARIABLE PR_LOCK3 :std_logic_vector(15 downto 0);
|
|
|
|
--Command Register
|
|
SIGNAL write : std_logic := '0';
|
|
SIGNAL cfg_write : std_logic := '0';
|
|
SIGNAL read_out : std_logic := '0';
|
|
|
|
SIGNAL fast_rd : boolean := true;
|
|
SIGNAL rd : boolean := false;
|
|
SIGNAL dual : boolean := false;
|
|
SIGNAL rd_jid : boolean := false;
|
|
|
|
SHARED VARIABLE hold_mode : boolean := false;
|
|
SHARED VARIABLE mpm_mode : boolean := false;
|
|
|
|
SHARED VARIABLE read_cnt : NATURAL := 0;
|
|
|
|
SIGNAL change_addr : std_logic := '0';
|
|
|
|
SIGNAL change_BP : std_logic := '0';
|
|
|
|
--FSM control signals
|
|
SIGNAL PDONE : std_logic := '1'; -- Page Prog. Done
|
|
SIGNAL PSTART : std_logic := '0'; --Start Page Programming
|
|
|
|
SIGNAL WDONE : std_logic := '1'; -- Write. Done
|
|
SIGNAL WSTART : std_logic := '0'; --Start Write
|
|
|
|
SIGNAL ESTART : std_logic := '0'; --Start Erase
|
|
SIGNAL EDONE : std_logic := '1'; --Erase Done
|
|
|
|
-- Sector and subsector addresses
|
|
SIGNAL SA : NATURAL RANGE 0 TO SecNum := 0;
|
|
SHARED VARIABLE sect : NATURAL RANGE 0 TO SecNum;
|
|
|
|
SIGNAL Byte_number : NATURAL RANGE 0 TO 255 := 0;
|
|
|
|
-- Sector is protect if '1'
|
|
SHARED VARIABLE Sec_Prot : std_logic_vector(SecNum downto 0) :=
|
|
(OTHERS => '0');
|
|
|
|
SHARED VARIABLE BP : std_logic_vector(2 downto 0) := "000";
|
|
|
|
SIGNAL Address : NATURAL RANGE 0 TO AddrRANGE := 0;
|
|
|
|
-- timing check violation
|
|
SIGNAL Viol : X01 := '0';
|
|
|
|
PROCEDURE ADDRHILO_SEC(
|
|
VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange;
|
|
VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange;
|
|
VARIABLE Addr : NATURAL) IS
|
|
VARIABLE sector : NATURAL RANGE 0 TO SecNum;
|
|
BEGIN
|
|
sector := Addr/16#10000#;
|
|
AddrLOW := sector*16#10000#;
|
|
AddrHIGH := sector*16#10000# + 16#0FFFF#;
|
|
END ADDRHILO_SEC;
|
|
|
|
PROCEDURE ADDRHILO_PG(
|
|
VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange;
|
|
VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange;
|
|
VARIABLE Addr : NATURAL) IS
|
|
VARIABLE page : NATURAL RANGE 0 TO PageNum;
|
|
BEGIN
|
|
page := Addr/16#100#;
|
|
AddrLOW := Page*16#100#;
|
|
AddrHIGH := Page*16#100# + 16#FF#;
|
|
END AddrHILO_PG;
|
|
|
|
PROCEDURE ADDRHILO_PB4(
|
|
VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange;
|
|
VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange;
|
|
VARIABLE Addr : NATURAL) IS
|
|
VARIABLE Sec : NATURAL RANGE 0 TO SecNum;
|
|
BEGIN
|
|
Sec := Addr/16#10000#;
|
|
IF Sec = 0 OR Sec = 1 OR Sec = SecNum OR Sec = SecNum - 1 THEN
|
|
AddrLOW := (Address/(SecSize_4+1))*(SecSize_4+1);
|
|
AddrHIGH := (Address/(SecSize_4+1))*(SecSize_4+1) + SecSize_4;
|
|
END IF;
|
|
END ADDRHILO_PB4;
|
|
|
|
PROCEDURE ADDRHILO_PB8(
|
|
VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange;
|
|
VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange;
|
|
VARIABLE Addr : NATURAL) IS
|
|
VARIABLE Sec : NATURAL RANGE 0 TO SecNum;
|
|
BEGIN
|
|
Sec := Addr/16#10000#;
|
|
IF Sec = 0 OR Sec = SecNum - 1 THEN
|
|
AddrLOW := (Address/(SecSize_8+1))*(SecSize_8+1);
|
|
AddrHIGH := (Address/(SecSize_8+1))*(SecSize_8+1) + SecSize_8;
|
|
ELSIF Sec = 1 THEN
|
|
AddrLOW := (Address/(SecSize_8+1))*(SecSize_8+1);
|
|
AddrHIGH := (Address/(SecSize_8+1))*(SecSize_8+1) + SecSize_8;
|
|
IF AddrHIGH > 16#1FFFF# THEN
|
|
AddrHIGH := 16#1FFFF#;
|
|
END IF;
|
|
ELSIF Sec = SecNum THEN
|
|
AddrLOW := (Address/(SecSize_8+1))*(SecSize_8+1);
|
|
AddrHIGH := (Address/(SecSize_8+1))*(SecSize_8+1) + SecSize_8;
|
|
IF AddrHIGH > 16#3FFFFF# THEN
|
|
AddrHIGH := 16#3FFFFF#;
|
|
END IF;
|
|
END IF;
|
|
END ADDRHILO_PB8;
|
|
|
|
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
|
|
VARIABLE Tviol_SI_SCK : X01 := '0';
|
|
VARIABLE TD_SI_SCK : VitalTimingDataType;
|
|
|
|
VARIABLE Tviol_HOLD_SCK : X01 := '0';
|
|
VARIABLE TD_HOLD_SCK : VitalTimingDataType;
|
|
|
|
VARIABLE Tviol_CS_SCK : X01 := '0';
|
|
VARIABLE TD_CS_SCK : VitalTimingDataType;
|
|
|
|
VARIABLE Tviol_WS_CS : X01 := '0';
|
|
VARIABLE TD_WS_CS : VitalTimingDataType;
|
|
|
|
VARIABLE Tviol_WH_CS : X01 := '0';
|
|
VARIABLE TD_WH_CS : VitalTimingDataType;
|
|
|
|
VARIABLE Pviol_CS_read : X01 := '0';
|
|
VARIABLE PD_CS_read : VitalPeriodDataType := VitalPeriodDataInit;
|
|
|
|
VARIABLE Pviol_CS_pgm : X01 := '0';
|
|
VARIABLE PD_CS_pgm : VitalPeriodDataType := VitalPeriodDataInit;
|
|
|
|
VARIABLE Pviol_SCK_serial_fast : X01 := '0';
|
|
VARIABLE PD_SCK_serial_fast : VitalPeriodDataType :=
|
|
VitalPeriodDataInit;
|
|
|
|
VARIABLE Pviol_SCK_dual : X01 := '0';
|
|
VARIABLE PD_SCK_dual : VitalPeriodDataType := VitalPeriodDataInit;
|
|
|
|
VARIABLE Pviol_SCK_rdid : X01 := '0';
|
|
VARIABLE PD_SCK_rdid : VitalPeriodDataType := VitalPeriodDataInit;
|
|
|
|
VARIABLE Pviol_SCK_serial : X01 := '0';
|
|
VARIABLE PD_SCK_serial : VitalPeriodDataType := VitalPeriodDataInit;
|
|
|
|
VARIABLE Pviol_SCK_serial_fast_rd: X01 := '0';
|
|
VARIABLE PD_SCK_serial_fast_rd : VitalPeriodDataType :=
|
|
VitalPeriodDataInit;
|
|
|
|
VARIABLE Pviol_SCK_serial_rd : X01 := '0';
|
|
VARIABLE PD_SCK_serial_rd : VitalPeriodDataType := VitalPeriodDataInit;
|
|
|
|
VARIABLE Pviol_SCK_serial_rdid : X01 := '0';
|
|
VARIABLE PD_SCK_serial_rdid: VitalPeriodDataType := VitalPeriodDataInit;
|
|
|
|
VARIABLE Pviol_SCK_dual_fast_rd: X01 := '0';
|
|
VARIABLE PD_SCK_dual_fast_rd : VitalPeriodDataType :=
|
|
VitalPeriodDataInit;
|
|
|
|
VARIABLE Violation : X01 := '0';
|
|
|
|
BEGIN
|
|
---------------------------------------------------------------------------
|
|
-- Timing Check Section
|
|
---------------------------------------------------------------------------
|
|
IF (TimingChecksOn) THEN
|
|
|
|
-- Setup/Hold Check between SI and SCK, serial mode
|
|
VitalSetupHoldCheck (
|
|
TestSignal => SIIn,
|
|
TestSignalName => "SI",
|
|
RefSignal => SCK_ipd,
|
|
RefSignalName => "SCK",
|
|
SetupHigh => tsetup_SI_SCK,
|
|
SetupLow => tsetup_SI_SCK,
|
|
HoldHigh => thold_SI_SCK,
|
|
HoldLow => thold_SI_SCK,
|
|
CheckEnabled => SIOut_z /= SIIn,
|
|
RefTransition => '/',
|
|
HeaderMsg => InstancePath & PartID,
|
|
TimingData => TD_SI_SCK,
|
|
Violation => Tviol_SI_SCK
|
|
);
|
|
|
|
-- Setup/Hold Check between HOLD# and SCK /
|
|
VitalSetupHoldCheck (
|
|
TestSignal => HOLDNegIn,
|
|
TestSignalName => "HOLD#",
|
|
RefSignal => SCK_ipd,
|
|
RefSignalName => "SCK",
|
|
SetupLow => tsetup_HOLDNeg_SCK,
|
|
SetupHigh => tsetup_HOLDNeg_SCK,
|
|
HoldLow => thold_HOLDNeg_SCK,
|
|
HoldHigh => thold_HOLDNeg_SCK,
|
|
CheckEnabled => QUAD = '1'
|
|
AND HOLDNegOut_zd /= HOLDNegIn,
|
|
RefTransition => '/',
|
|
HeaderMsg => InstancePath & PartID,
|
|
TimingData => TD_HOLD_SCK,
|
|
Violation => Tviol_HOLD_SCK
|
|
);
|
|
|
|
-- Setup/Hold Check between CS# and SCK
|
|
VitalSetupHoldCheck (
|
|
TestSignal => CSNeg_ipd,
|
|
TestSignalName => "CS#",
|
|
RefSignal => SCK_ipd,
|
|
RefSignalName => "SCK",
|
|
SetupHigh => tsetup_CSNeg_SCK,
|
|
SetupLow => tsetup_CSNeg_SCK,
|
|
HoldHigh => thold_CSNeg_SCK,
|
|
HoldLow => thold_CSNeg_SCK,
|
|
CheckEnabled => true,
|
|
RefTransition => '/',
|
|
HeaderMsg => InstancePath & PartID,
|
|
TimingData => TD_CS_SCK,
|
|
Violation => Tviol_CS_SCK
|
|
);
|
|
|
|
-- Setup Check between W# and CS# \
|
|
VitalSetupHoldCheck (
|
|
TestSignal => WPNegIn,
|
|
TestSignalName => "W#",
|
|
RefSignal => CSNeg_ipd,
|
|
RefSignalName => "CS#",
|
|
SetupHigh => tsetup_WPNeg_CSNeg,
|
|
CheckEnabled => true,
|
|
RefTransition => '\',
|
|
HeaderMsg => InstancePath & PartID,
|
|
TimingData => TD_WS_CS,
|
|
Violation => Tviol_WS_CS
|
|
);
|
|
|
|
-- Hold Check between W# and CS# /
|
|
VitalSetupHoldCheck (
|
|
TestSignal => WPNegIn,
|
|
TestSignalName => "W#",
|
|
RefSignal => CSNeg_ipd,
|
|
RefSignalName => "CS#",
|
|
HoldHigh => thold_WPNeg_CSNeg,
|
|
CheckEnabled => SRWD = '1' AND WEL = '1' AND QUAD = '0',
|
|
RefTransition => '/',
|
|
HeaderMsg => InstancePath & PartID,
|
|
TimingData => TD_WH_CS,
|
|
Violation => Tviol_WH_CS
|
|
);
|
|
|
|
-- Period Check CS# for Program/Erase, serial mode
|
|
VitalPeriodPulseCheck (
|
|
TestSignal => CSNeg_ipd,
|
|
TestSignalName => "CS#",
|
|
PulseWidthHigh => tpw_CSNeg_pgm_posedge,
|
|
PeriodData => PD_CS_pgm,
|
|
XOn => XOn,
|
|
MsgOn => MsgOn,
|
|
Violation => Pviol_CS_pgm,
|
|
HeaderMsg => InstancePath & PartID,
|
|
CheckEnabled => TRUE );
|
|
|
|
-- Period Check CS# for READ, serial mode
|
|
VitalPeriodPulseCheck (
|
|
TestSignal => CSNeg_ipd,
|
|
TestSignalName => "CS#",
|
|
PulseWidthHigh => tpw_CSNeg_read_posedge,
|
|
PeriodData => PD_CS_read,
|
|
XOn => XOn,
|
|
MsgOn => MsgOn,
|
|
Violation => Pviol_CS_read,
|
|
HeaderMsg => InstancePath & PartID,
|
|
CheckEnabled => rd );
|
|
|
|
-- Period Check SCK for READ, serial mode
|
|
VitalPeriodPulseCheck (
|
|
TestSignal => SCK_ipd,
|
|
TestSignalName => "SCK",
|
|
PulseWidthLow => tpw_SCK_serial_negedge,
|
|
PulseWidthHigh => tpw_SCK_serial_posedge,
|
|
PeriodData => PD_SCK_serial,
|
|
XOn => XOn,
|
|
MsgOn => MsgOn,
|
|
Violation => Pviol_SCK_serial,
|
|
HeaderMsg => InstancePath & PartID,
|
|
CheckEnabled => rd);
|
|
|
|
-- Period Check SCK for RDID, serial mode
|
|
VitalPeriodPulseCheck (
|
|
TestSignal => SCK_ipd,
|
|
TestSignalName => "SCK",
|
|
PulseWidthLow => tpw_SCK_rd_jid_negedge,
|
|
PulseWidthHigh => tpw_SCK_rd_jid_posedge,
|
|
PeriodData => PD_SCK_rdid,
|
|
XOn => XOn,
|
|
MsgOn => MsgOn,
|
|
Violation => Pviol_SCK_rdid,
|
|
HeaderMsg => InstancePath & PartID,
|
|
CheckEnabled => rd_jid);
|
|
|
|
-- Period Check SCK for FAST_READ, serial mode
|
|
VitalPeriodPulseCheck (
|
|
TestSignal => SCK_ipd,
|
|
TestSignalName => "SCK",
|
|
PulseWidthLow => tpw_SCK_serial_fast_negedge,
|
|
PulseWidthHigh => tpw_SCK_serial_fast_posedge,
|
|
PeriodData => PD_SCK_serial_fast,
|
|
XOn => XOn,
|
|
MsgOn => MsgOn,
|
|
Violation => Pviol_SCK_serial_fast,
|
|
HeaderMsg => InstancePath & PartID,
|
|
CheckEnabled => fast_rd );
|
|
|
|
-- Period Check SCK for DUAL_READ, serial mode
|
|
VitalPeriodPulseCheck (
|
|
TestSignal => SCK_ipd,
|
|
TestSignalName => "SCK",
|
|
PulseWidthLow => tpw_SCK_dual_negedge,
|
|
PulseWidthHigh => tpw_SCK_dual_posedge,
|
|
PeriodData => PD_SCK_dual,
|
|
XOn => XOn,
|
|
MsgOn => MsgOn,
|
|
Violation => Pviol_SCK_dual,
|
|
HeaderMsg => InstancePath & PartID,
|
|
CheckEnabled => dual);
|
|
|
|
-- Period Check SCK for READ, serial mode
|
|
VitalPeriodPulseCheck (
|
|
TestSignal => SCK_ipd,
|
|
TestSignalName => "SCK",
|
|
Period => tperiod_SCK_serial_rd,
|
|
PeriodData => PD_SCK_serial_rd,
|
|
XOn => XOn,
|
|
MsgOn => MsgOn,
|
|
Violation => Pviol_SCK_serial_rd,
|
|
HeaderMsg => InstancePath & PartID,
|
|
CheckEnabled => rd );
|
|
|
|
-- Period Check SCK for RDID, serial mode
|
|
VitalPeriodPulseCheck (
|
|
TestSignal => SCK_ipd,
|
|
TestSignalName => "SCK",
|
|
Period => tperiod_SCK_serial_rd_jid,
|
|
PeriodData => PD_SCK_serial_rdid,
|
|
XOn => XOn,
|
|
MsgOn => MsgOn,
|
|
Violation => Pviol_SCK_serial_rdid,
|
|
HeaderMsg => InstancePath & PartID,
|
|
CheckEnabled => rd_jid );
|
|
|
|
-- Period Check SCK for other than READ, serial mode
|
|
VitalPeriodPulseCheck (
|
|
TestSignal => SCK_ipd,
|
|
TestSignalName => "SCK",
|
|
Period => tperiod_SCK_serial_fast_rd,
|
|
PeriodData => PD_SCK_serial_fast_rd,
|
|
XOn => XOn,
|
|
MsgOn => MsgOn,
|
|
Violation => Pviol_SCK_serial_fast_rd,
|
|
HeaderMsg => InstancePath & PartID,
|
|
CheckEnabled => fast_rd );
|
|
|
|
-- Period Check SCK for other than READ, serial mode
|
|
VitalPeriodPulseCheck (
|
|
TestSignal => SCK_ipd,
|
|
TestSignalName => "SCK",
|
|
Period => tperiod_SCK_dual_fast_rd,
|
|
PeriodData => PD_SCK_dual_fast_rd,
|
|
XOn => XOn,
|
|
MsgOn => MsgOn,
|
|
Violation => Pviol_SCK_dual_fast_rd,
|
|
HeaderMsg => InstancePath & PartID,
|
|
CheckEnabled => dual );
|
|
|
|
Violation := Tviol_SI_SCK OR
|
|
Tviol_HOLD_SCK OR
|
|
Tviol_CS_SCK OR
|
|
Tviol_WS_CS OR
|
|
Tviol_WH_CS OR
|
|
Pviol_CS_read OR
|
|
Pviol_CS_pgm OR
|
|
Pviol_SCK_serial_fast OR
|
|
Pviol_SCK_dual OR
|
|
Pviol_SCK_rdid OR
|
|
Pviol_SCK_serial OR
|
|
Pviol_SCK_serial_rd OR
|
|
Pviol_SCK_serial_rdid OR
|
|
Pviol_SCK_serial_fast_rd OR
|
|
Pviol_SCK_dual_fast_rd;
|
|
|
|
Viol <= Violation;
|
|
|
|
ASSERT Violation = '0'
|
|
REPORT InstancePath & partID & ": simulation may be" &
|
|
" inaccurate due to timing violations"
|
|
SEVERITY WARNING;
|
|
|
|
END IF;
|
|
END PROCESS VITALTimingCheck;
|
|
|
|
----------------------------------------------------------------------------
|
|
-- sequential process for FSM state transition
|
|
----------------------------------------------------------------------------
|
|
StateTransition : PROCESS(next_state, PoweredUp)
|
|
|
|
BEGIN
|
|
IF PoweredUp = '1' THEN
|
|
current_state <= next_state;
|
|
END IF;
|
|
END PROCESS StateTransition;
|
|
|
|
---------------------------------------------------------------------------
|
|
-- Write cycle decode
|
|
---------------------------------------------------------------------------
|
|
BusCycleDecode : PROCESS(SCK_ipd, CSNeg_ipd, HOLDNeg_pullup, SIIn, RES_in)
|
|
|
|
TYPE bus_cycle_type IS (STAND_BY,
|
|
CODE_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 data_cnt : NATURAL := 0;
|
|
VARIABLE addr_cnt : NATURAL := 0;
|
|
VARIABLE code_cnt : NATURAL := 0;
|
|
VARIABLE mode_cnt : NATURAL := 0;
|
|
VARIABLE dummy_cnt : NATURAL := 0;
|
|
VARIABLE bit_cnt : NATURAL := 0;
|
|
VARIABLE Data_in : std_logic_vector(2047 downto 0)
|
|
:= (others => '0');
|
|
VARIABLE 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 code : std_logic_vector(7 downto 0);
|
|
VARIABLE code_in : std_logic_vector(7 downto 0);
|
|
VARIABLE Byte_slv : std_logic_vector(7 downto 0);
|
|
VARIABLE addr_bytes : std_logic_vector(HiAddrBit downto 0);
|
|
VARIABLE Address_in : std_logic_vector(23 downto 0);
|
|
VARIABLE mode_bytes : std_logic_vector(7 downto 0);
|
|
VARIABLE mode_in : std_logic_vector(7 downto 0);
|
|
BEGIN
|
|
|
|
IF rising_edge(CSNeg_ipd) AND NOT(bus_cycle_state = DATA_BYTES)
|
|
AND NOT(bus_cycle_state = DUMMY_BYTES) THEN
|
|
bus_cycle_state := STAND_BY;
|
|
ELSE
|
|
CASE bus_cycle_state IS
|
|
WHEN STAND_BY =>
|
|
IF falling_edge(CSNeg_ipd) THEN
|
|
Instruct <= NONE;
|
|
write <= '1';
|
|
code_cnt := 0;
|
|
addr_cnt := 0;
|
|
data_cnt := 0;
|
|
mode_cnt := 0;
|
|
dummy_cnt := 0;
|
|
bus_cycle_state := CODE_BYTE;
|
|
END IF;
|
|
|
|
WHEN CODE_BYTE =>
|
|
IF rising_edge(SCK_ipd) AND
|
|
((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD ='1') THEN
|
|
Code_in(code_cnt) := SIIn;
|
|
code_cnt := code_cnt + 1;
|
|
IF code_cnt = BYTE THEN
|
|
--MSB first
|
|
FOR I IN 7 DOWNTO 0 LOOP
|
|
code(i) := code_in(7-i);
|
|
END LOOP;
|
|
|
|
CASE code IS
|
|
WHEN "00000110" => --06h
|
|
Instruct <= WREN;
|
|
bus_cycle_state := DATA_BYTES;
|
|
WHEN "00000100" => --04h
|
|
Instruct <= WRDI;
|
|
bus_cycle_state := DATA_BYTES;
|
|
WHEN "00000001" => --01h
|
|
Instruct <= WRR;
|
|
bus_cycle_state := DATA_BYTES;
|
|
WHEN "00000101" => --05h
|
|
Instruct <= RDSR;
|
|
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 "10011111" => --9Fh
|
|
Instruct <= RDID;
|
|
bus_cycle_state := DATA_BYTES;
|
|
WHEN "10010000" =>
|
|
Instruct <= READ_ID; --90h
|
|
bus_cycle_state := ADDRESS_BYTES;
|
|
WHEN "10101011" =>
|
|
Instruct <= RES_READ_ES; --ABh
|
|
bus_cycle_state := DUMMY_BYTES;
|
|
WHEN "11011000" => --D8h
|
|
Instruct <= SE;
|
|
bus_cycle_state := ADDRESS_BYTES;
|
|
WHEN "11000111" | "01100000" => --C7h or 60h
|
|
Instruct <= BE;
|
|
bus_cycle_state := DATA_BYTES;
|
|
WHEN "00000010" => --02h
|
|
Instruct <= PP;
|
|
bus_cycle_state := ADDRESS_BYTES;
|
|
WHEN "00110010" => --32h
|
|
Instruct <= QPP;
|
|
bus_cycle_state := ADDRESS_BYTES;
|
|
WHEN "10111001" => --B9h
|
|
Instruct <= DP;
|
|
bus_cycle_state := DATA_BYTES;
|
|
WHEN "00110000" => --30h
|
|
Instruct <= CLSR;
|
|
bus_cycle_state := DATA_BYTES;
|
|
WHEN "00110101" => --35h
|
|
Instruct <= RCR;
|
|
bus_cycle_state := DATA_BYTES;
|
|
WHEN "00100000" => --20h
|
|
Instruct <= P4E;
|
|
bus_cycle_state := ADDRESS_BYTES;
|
|
WHEN "01000000" =>--40h
|
|
Instruct <= P8E;
|
|
bus_cycle_state := ADDRESS_BYTES;
|
|
WHEN "01000010" => --42h
|
|
Instruct <= OTPP;
|
|
bus_cycle_state := ADDRESS_BYTES;
|
|
WHEN "01001011" => --4Bh
|
|
Instruct <= OTPR;
|
|
bus_cycle_state := ADDRESS_BYTES;
|
|
WHEN "00111011" => --3Bh
|
|
Instruct <= DUAL_READ;
|
|
bus_cycle_state := ADDRESS_BYTES;
|
|
WHEN "01101011" => --6Bh
|
|
Instruct <= QUAD_READ;
|
|
bus_cycle_state := ADDRESS_BYTES;
|
|
WHEN "10111011" => --BBh
|
|
Instruct <= DH_READ;
|
|
bus_cycle_state := ADDRESS_BYTES;
|
|
WHEN "11101011" => --EBh
|
|
Instruct <= QH_READ;
|
|
bus_cycle_state := ADDRESS_BYTES;
|
|
WHEN others =>
|
|
null;
|
|
END CASE;
|
|
END IF;
|
|
END IF;
|
|
|
|
WHEN ADDRESS_BYTES =>
|
|
IF rising_edge(SCK_ipd) THEN
|
|
IF ((Instruct=FAST_READ OR Instruct=OTPR
|
|
OR Instruct=DUAL_READ) AND
|
|
((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD ='1'))
|
|
OR (Instruct=QUAD_READ AND QUAD = '1') THEN
|
|
Address_in(addr_cnt) := SIIn;
|
|
addr_cnt := addr_cnt + 1;
|
|
IF addr_cnt = 3*BYTE THEN
|
|
FOR I IN 23 DOWNTO 23-HiAddrBit LOOP
|
|
addr_bytes(23-i) := Address_in(i);
|
|
END LOOP;
|
|
Address <= to_nat(addr_bytes);
|
|
change_addr <= '1','0' AFTER 1 ns;
|
|
bus_cycle_state := DUMMY_BYTES;
|
|
END IF;
|
|
ELSIF Instruct = DH_READ AND
|
|
((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD ='1') 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 = 12 THEN
|
|
addr_cnt := 0;
|
|
FOR I IN 23 DOWNTO 23-HiAddrBit LOOP
|
|
addr_bytes(23-i) := Address_in(i);
|
|
END LOOP;
|
|
Address <= to_nat(addr_bytes);
|
|
change_addr <= '1','0' AFTER 1 ns;
|
|
bus_cycle_state := MODE_BYTE;
|
|
END IF;
|
|
ELSE
|
|
mpm_mode := FALSE;
|
|
bus_cycle_state := STAND_BY;
|
|
END IF;
|
|
ELSIF Instruct = QH_READ THEN
|
|
IF QUAD = '1' 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 = 6 THEN
|
|
addr_cnt := 0;
|
|
FOR I IN 23 DOWNTO 23-HiAddrBit LOOP
|
|
addr_bytes(23-i) := Address_in(i);
|
|
END LOOP;
|
|
Address <= to_nat(addr_bytes);
|
|
change_addr <= '1','0' AFTER 1 ns;
|
|
bus_cycle_state := MODE_BYTE;
|
|
END IF;
|
|
ELSE
|
|
mpm_mode := FALSE;
|
|
bus_cycle_state := STAND_BY;
|
|
END IF;
|
|
ELSE
|
|
bus_cycle_state := STAND_BY;
|
|
END IF;
|
|
ELSIF ((HOLDNeg_pullup='1' AND QUAD='0') OR
|
|
QUAD ='1') THEN
|
|
Address_in(addr_cnt) := SIIn;
|
|
addr_cnt := addr_cnt + 1;
|
|
IF addr_cnt = 3*BYTE THEN
|
|
FOR I IN 23 DOWNTO 23-HiAddrBit LOOP
|
|
addr_bytes(23-i) := Address_in(i);
|
|
END LOOP;
|
|
Address <= to_nat(addr_bytes);
|
|
change_addr <= '1','0' AFTER 1 ns;
|
|
bus_cycle_state := DATA_BYTES;
|
|
END IF;
|
|
END IF;
|
|
END IF;
|
|
|
|
WHEN MODE_BYTE =>
|
|
IF rising_edge(SCK_ipd) THEN
|
|
IF Instruct=DH_READ AND
|
|
((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD ='1') 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_bytes(i) := mode_in(7-i);
|
|
END LOOP;
|
|
bus_cycle_state := DATA_BYTES;
|
|
END IF;
|
|
ELSIF Instruct=QH_READ AND QUAD = '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_bytes(i) := mode_in(7-i);
|
|
END LOOP;
|
|
bus_cycle_state := DUMMY_BYTES;
|
|
END IF;
|
|
END IF;
|
|
dummy_cnt := 0;
|
|
END IF;
|
|
|
|
WHEN DUMMY_BYTES =>
|
|
IF rising_edge(SCK_ipd) THEN
|
|
IF QUAD = '1' AND (Instruct=QUAD_READ
|
|
OR Instruct=QH_READ) THEN
|
|
dummy_cnt := dummy_cnt + 1;
|
|
IF dummy_cnt = BYTE AND Instruct=QUAD_READ THEN
|
|
bus_cycle_state := DATA_BYTES;
|
|
ELSIF dummy_cnt = BYTE/2 AND Instruct=QH_READ THEN
|
|
bus_cycle_state := DATA_BYTES;
|
|
END IF;
|
|
ELSIF ((HOLDNeg_pullup='1' AND QUAD='0') OR
|
|
QUAD ='1') THEN
|
|
dummy_cnt := dummy_cnt + 1;
|
|
IF dummy_cnt = BYTE THEN
|
|
IF Instruct=FAST_READ OR Instruct=OTPR OR
|
|
Instruct=DUAL_READ THEN
|
|
bus_cycle_state := DATA_BYTES;
|
|
END IF;
|
|
ELSIF dummy_cnt = 3*BYTE THEN
|
|
bus_cycle_state := DATA_BYTES;
|
|
END IF;
|
|
END IF;
|
|
END IF;
|
|
|
|
IF rising_edge(CSNeg_ipd) THEN
|
|
IF (((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD ='1')
|
|
AND dummy_cnt = 0 AND Instruct = RES_READ_ES) THEN
|
|
write <= '0';
|
|
END IF;
|
|
bus_cycle_state := STAND_BY;
|
|
END IF;
|
|
|
|
WHEN DATA_BYTES =>
|
|
IF falling_edge(SCK_ipd) AND CSNeg_ipd = '0' THEN
|
|
IF ((Instruct = READ OR Instruct = FAST_READ
|
|
OR Instruct = DUAL_READ OR Instruct = DH_READ
|
|
OR Instruct = RES_READ_ES OR Instruct = RDID
|
|
OR Instruct = READ_ID OR Instruct = RDSR
|
|
OR Instruct = RCR OR Instruct = OTPR)
|
|
AND ((HOLDNeg_pullup='1' AND QUAD='0') OR QUAD ='1'))
|
|
OR ((Instruct=QUAD_READ OR Instruct=QH_READ)
|
|
AND QUAD = '1') THEN
|
|
read_out <= '1', '0' AFTER 1 ns;
|
|
END IF;
|
|
END IF;
|
|
IF rising_edge(SCK_ipd) THEN
|
|
IF QUAD = '1' AND Instruct=QPP THEN
|
|
quad_nybble := HOLDNegIn & WPNegIn & SOIn & SIIn;
|
|
IF data_cnt > 511 THEN
|
|
--In case of quad mode and QPP,
|
|
--if more than 512 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;
|
|
ELSIF ((HOLDNeg_pullup='1' AND QUAD='0') OR
|
|
QUAD ='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;
|
|
END IF;
|
|
END IF;
|
|
|
|
IF rising_edge(CSNeg_ipd) THEN
|
|
IF mpm_mode AND mode_bytes(7 downto 4) = "1010"
|
|
AND (Instruct = DH_READ OR Instruct = QH_READ) THEN
|
|
bus_cycle_state := ADDRESS_BYTES;
|
|
ELSE
|
|
mpm_mode := FALSE;
|
|
bus_cycle_state := STAND_BY;
|
|
END IF;
|
|
CASE Instruct IS
|
|
WHEN WREN | WRDI | DP | BE | SE | P4E | P8E
|
|
| CLSR =>
|
|
IF ((HOLDNeg_pullup='1' AND QUAD='0') OR
|
|
QUAD ='1') THEN
|
|
IF data_cnt = 0 THEN
|
|
write <= '0';
|
|
END IF;
|
|
END IF;
|
|
WHEN RES_READ_ES =>
|
|
IF ((HOLDNeg_pullup='1' AND QUAD='0') OR
|
|
QUAD ='1') THEN
|
|
write <= '0';
|
|
END IF;
|
|
WHEN WRR =>
|
|
IF ((HOLDNeg_pullup='1' AND QUAD='0') OR
|
|
QUAD ='1') THEN
|
|
IF ((data_cnt mod 8) = 0 AND
|
|
data_cnt > 0) THEN
|
|
IF data_cnt = 8 THEN
|
|
write <= '0';
|
|
cfg_write <= '0';
|
|
FOR i IN 0 TO 7 LOOP
|
|
Status_reg_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';
|
|
cfg_write <= '1';
|
|
FOR i IN 0 TO 7 LOOP
|
|
Status_reg_in(i) <=
|
|
Data_in(7-i);
|
|
Sec_conf_reg_in(i) <=
|
|
Data_in(15-i);
|
|
END LOOP;
|
|
END IF;
|
|
END IF;
|
|
END IF;
|
|
|
|
WHEN PP =>
|
|
IF ((HOLDNeg_pullup='1' AND QUAD='0') OR
|
|
QUAD ='1') THEN
|
|
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;
|
|
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 > 512 THEN
|
|
Byte_number <= 255;
|
|
ELSE
|
|
Byte_number <= data_cnt/2-1;
|
|
END IF;
|
|
END IF;
|
|
END IF;
|
|
|
|
WHEN OTPP =>
|
|
IF ((HOLDNeg_pullup='1' AND QUAD='0') OR
|
|
QUAD ='1') THEN
|
|
IF data_cnt = 8 THEN
|
|
write <= '0';
|
|
FOR J IN 7 DOWNTO 0 LOOP
|
|
Byte_slv(j) := Data_in(7-j);
|
|
END LOOP;
|
|
WOTPByte <= to_nat(Byte_slv);
|
|
END IF;
|
|
END IF;
|
|
|
|
WHEN others =>
|
|
null;
|
|
END CASE;
|
|
END IF;
|
|
|
|
END CASE;
|
|
END IF;
|
|
|
|
END PROCESS BusCycleDecode;
|
|
|
|
---------------------------------------------------------------------------
|
|
-- Timing control for the Page Program
|
|
---------------------------------------------------------------------------
|
|
ProgTime : PROCESS(PSTART)
|
|
VARIABLE pob : time;
|
|
BEGIN
|
|
IF LongTimming THEN
|
|
pob := tdevice_PP;
|
|
ELSE
|
|
pob := tdevice_PP / 100;
|
|
END IF;
|
|
IF rising_edge(PSTART) AND PDONE = '1' THEN
|
|
IF Sec_Prot(SA) = '0' THEN
|
|
PDONE <= '0', '1' AFTER pob;
|
|
END IF;
|
|
END IF;
|
|
END PROCESS ProgTime;
|
|
|
|
---------------------------------------------------------------------------
|
|
-- Timing control for the Write Status Register
|
|
---------------------------------------------------------------------------
|
|
WriteTime : PROCESS(WSTART)
|
|
VARIABLE wob : time;
|
|
BEGIN
|
|
IF LongTimming THEN
|
|
wob := tdevice_WR;
|
|
ELSE
|
|
wob := tdevice_WR / 100;
|
|
END IF;
|
|
IF rising_edge(WSTART) AND WDONE = '1' THEN
|
|
WDONE <= '0', '1' AFTER wob;
|
|
END IF;
|
|
END PROCESS WriteTime;
|
|
|
|
---------------------------------------------------------------------------
|
|
-- Timing control for the Bulk Erase
|
|
---------------------------------------------------------------------------
|
|
ErsTime : PROCESS(ESTART)
|
|
VARIABLE seo : time;
|
|
VARIABLE beo : time;
|
|
VARIABLE peo : time;
|
|
VARIABLE duration : time;
|
|
BEGIN
|
|
IF LongTimming THEN
|
|
seo := tdevice_SE;
|
|
beo := tdevice_BE;
|
|
peo := tdevice_PE;
|
|
ELSE
|
|
seo := tdevice_SE / 1000;
|
|
beo := tdevice_BE / 1000;
|
|
peo := tdevice_PE / 1000;
|
|
END IF;
|
|
IF rising_edge(ESTART) AND EDONE = '1' THEN
|
|
IF Instruct = BE THEN
|
|
duration := beo;
|
|
ELSIF Instruct = P4E OR Instruct = P8E THEN
|
|
duration := peo;
|
|
ELSE --Instruct = SE
|
|
duration := seo;
|
|
END IF;
|
|
EDONE <= '0', '1' AFTER duration;
|
|
END IF;
|
|
END PROCESS ErsTime;
|
|
|
|
CheckCEOnPowerUP :PROCESS
|
|
BEGIN
|
|
IF CSNeg /= '1' THEN
|
|
REPORT InstancePath & partID &
|
|
": Device is selected during Power Up"
|
|
SEVERITY WARNING;
|
|
END IF;
|
|
WAIT;
|
|
END PROCESS;
|
|
|
|
---------------------------------------------------------------------------
|
|
-- Main Behavior Process
|
|
-- combinational process for next state generation
|
|
---------------------------------------------------------------------------
|
|
StateGen :PROCESS(write, CSNeg, WDONE, PDONE, EDONE, DP_out)
|
|
|
|
BEGIN
|
|
-----------------------------------------------------------------------
|
|
-- Functionality Section
|
|
-----------------------------------------------------------------------
|
|
|
|
CASE current_state IS
|
|
WHEN IDLE =>
|
|
IF falling_edge(write) THEN
|
|
IF Instruct = WRR AND WEL = '1'
|
|
AND not(SRWD='1' AND WPNeg_pullup='0' AND QUAD='0') THEN
|
|
-- can not execute if HPM is entered
|
|
-- or if WEL bit is zero
|
|
next_state <= WRITE_SR;
|
|
ELSIF (Instruct = PP OR Instruct = QPP) AND WEL = '1' THEN
|
|
sect := Address / 16#10000#;
|
|
IF Sec_Prot(sect) = '0' THEN
|
|
next_state <= PAGE_PG;
|
|
END IF;
|
|
ELSIF Instruct = OTPP AND WEL = '1' THEN
|
|
IF Address = 256 OR Address = 257 OR
|
|
((Address >= 258 AND Address <= 273) AND
|
|
PR_LOCK1((Address-258)/8) = '1') OR Address = 274 OR
|
|
Address = 275 OR((Address >= 276 AND Address <= 531)
|
|
AND PR_LOCK2((Address-276)/16) = '1') OR Address = 532
|
|
OR Address = 533 OR((Address >= 534 AND Address <= 767)
|
|
AND PR_LOCK3((Address-534)/16) = '1') THEN
|
|
next_state <= OTP_PG;
|
|
END IF;
|
|
ELSIF Instruct = SE AND WEL = '1' THEN
|
|
sect := Address / 16#10000#;
|
|
IF Sec_Prot(sect) = '0' THEN
|
|
next_state <= SECTOR_ER;
|
|
END IF;
|
|
ELSIF Instruct = P4E AND WEL = '1' THEN
|
|
sect := Address / 16#10000#;
|
|
IF Sec_Prot(sect) = '0' AND (((sect=0 OR sect=1)
|
|
AND TBPARM='0') OR ((sect=SecNum OR sect=SecNum-1)
|
|
AND TBPARM='1')) THEN
|
|
next_state <= P4_ER;
|
|
END IF;
|
|
ELSIF Instruct = P8E AND WEL = '1' THEN
|
|
sect := Address / 16#10000#;
|
|
IF Sec_Prot(sect) = '0' AND (((sect=0 OR sect=1)
|
|
AND TBPARM='0') OR ((sect=SecNum OR sect=SecNum-1)
|
|
AND TBPARM='1')) THEN
|
|
next_state <= P8_ER;
|
|
END IF;
|
|
ELSIF Instruct = BE AND WEL = '1' AND
|
|
(BP0='0' AND BP1='0' AND BP2='0') THEN
|
|
next_state <= BULK_ER;
|
|
ELSIF Instruct = DP THEN
|
|
next_state <= DP_DOWN_WAIT;
|
|
ELSE
|
|
next_state <= IDLE;
|
|
END IF;
|
|
END IF;
|
|
|
|
WHEN WRITE_SR =>
|
|
IF rising_edge(WDONE) THEN
|
|
next_state <= IDLE;
|
|
END IF;
|
|
|
|
WHEN PAGE_PG =>
|
|
IF rising_edge(PDONE) THEN
|
|
next_state <= IDLE;
|
|
END IF;
|
|
|
|
WHEN OTP_PG =>
|
|
IF rising_edge(PDONE) THEN
|
|
next_state <= IDLE;
|
|
END IF;
|
|
|
|
WHEN BULK_ER | SECTOR_ER | P4_ER | P8_ER =>
|
|
IF rising_edge(EDONE) THEN
|
|
next_state <= IDLE;
|
|
END IF;
|
|
|
|
WHEN DP_DOWN_WAIT =>
|
|
IF rising_edge(DP_out) THEN
|
|
next_state <= DP_DOWN;
|
|
END IF;
|
|
|
|
WHEN DP_DOWN =>
|
|
IF falling_edge(write) AND Instruct = RES_READ_ES THEN
|
|
next_state <= IDLE;
|
|
END IF;
|
|
|
|
END CASE;
|
|
|
|
END PROCESS StateGen;
|
|
|
|
---------------------------------------------------------------------------
|
|
--FSM Output generation and general funcionality
|
|
---------------------------------------------------------------------------
|
|
Functional : PROCESS(write,read_out, WDONE, PDONE, EDONE, current_state,
|
|
CSNeg_ipd, HOLDNeg_pullup, Instruct, Address, WByte,
|
|
DP_out, RES_out, change_addr, PoweredUp, WPNeg_pullup)
|
|
--Common Flash Interface Query codes
|
|
TYPE CFItype IS ARRAY (16#07# TO 16#50#) OF
|
|
INTEGER RANGE -1 TO 16#FF#;
|
|
TYPE WDataType IS ARRAY (0 TO 255) OF INTEGER RANGE -1 TO MaxData;
|
|
|
|
VARIABLE CFI_array : CFItype := (OTHERS => -1);
|
|
VARIABLE WData : WDataType := (OTHERS => 0);
|
|
VARIABLE WOTPData : INTEGER RANGE -1 to MaxData;
|
|
VARIABLE oe : boolean := FALSE;
|
|
|
|
VARIABLE AddrLo : NATURAL;
|
|
VARIABLE AddrHi : NATURAL;
|
|
VARIABLE Addr : NATURAL;
|
|
VARIABLE Addr_tmp : NATURAL;
|
|
|
|
VARIABLE read_addr : NATURAL RANGE 0 TO AddrRANGE;
|
|
VARIABLE data_out : std_logic_vector(7 downto 0);
|
|
VARIABLE ident_out : std_logic_vector(647 downto 0);
|
|
VARIABLE CFI_array_tmp : std_logic_vector(591 downto 0);
|
|
|
|
VARIABLE old_bit : std_logic_vector(7 downto 0);
|
|
VARIABLE new_bit : std_logic_vector(7 downto 0);
|
|
VARIABLE old_int : INTEGER RANGE -1 to MaxData;
|
|
VARIABLE new_int : INTEGER RANGE -1 to MaxData;
|
|
VARIABLE wr_cnt : NATURAL RANGE 0 TO 255;
|
|
|
|
VARIABLE sect : NATURAL RANGE 0 TO SecNum;
|
|
VARIABLE cnt : NATURAL RANGE 0 TO 256 := 0;
|
|
|
|
BEGIN
|
|
-----------------------------------------------------------------------
|
|
-- Functionality Section
|
|
-----------------------------------------------------------------------
|
|
|
|
oe := rising_edge(read_out) AND PoweredUp = '1';
|
|
|
|
IF Instruct'EVENT THEN
|
|
read_cnt := 0;
|
|
fast_rd <= true;
|
|
rd_jid <= false;
|
|
dual <= false;
|
|
rd <= false;
|
|
IF Instruct = DH_READ OR Instruct = QH_READ THEN
|
|
mpm_mode := TRUE;
|
|
END IF;
|
|
END IF;
|
|
|
|
IF rising_edge(PoweredUp) THEN
|
|
|
|
FREEZE := '0';
|
|
--When BPNV is set to '1'. the BP2-0 bits in Status Register are
|
|
--volatile and will be reset binary 111 after power-on reset
|
|
IF BPNV = '1' AND FREEZE = '0' THEN
|
|
BP0 := '1';
|
|
BP1 := '1';
|
|
BP2 := '1';
|
|
BP := BP2 & BP1 & BP0;
|
|
change_BP <= '1', '0' AFTER 1 ns;
|
|
END IF;
|
|
END IF;
|
|
|
|
IF rising_edge(change_addr) THEN
|
|
read_addr := Address;
|
|
END IF;
|
|
|
|
IF RES_out'EVENT AND RES_out = '1' THEN
|
|
RES_in <= '0';
|
|
END IF;
|
|
|
|
CASE current_state IS
|
|
WHEN IDLE =>
|
|
IF falling_edge(write) THEN
|
|
read_cnt := 0;
|
|
IF RES_in = '1' AND Instruct /= DP THEN
|
|
ASSERT false
|
|
REPORT InstancePath & partID & "Command results" &
|
|
" can be corrupted, a delay of tRES" &
|
|
" currently in progress."
|
|
SEVERITY WARNING;
|
|
END IF;
|
|
IF Instruct = WREN THEN
|
|
WEL := '1';
|
|
ELSIF Instruct = WRDI THEN
|
|
WEL := '0';
|
|
ELSIF Instruct = WRR AND WEL = '1' THEN
|
|
IF not(SRWD='1' AND WPNeg_pullup='0' AND QUAD='0') THEN
|
|
-- can not execute if HPM is entered
|
|
-- or if WEL bit is zero
|
|
WSTART <= '1', '0' AFTER 1 ns;
|
|
WIP := '1';
|
|
ELSE
|
|
WEL := '0';
|
|
END IF;
|
|
ELSIF (Instruct = PP OR Instruct = QPP) AND WEL = '1' THEN
|
|
sect := Address / 16#10000#;
|
|
IF Sec_Prot(sect) = '0' THEN
|
|
PSTART <= '1', '0' AFTER 1 ns;
|
|
WIP := '1';
|
|
SA <= sect;
|
|
Addr := Address;
|
|
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 = OTPP AND WEL = '1' THEN
|
|
IF Address = 256 OR Address = 257 OR
|
|
((Address >= 258 AND Address <= 273) AND
|
|
PR_LOCK1((Address-258)/8)='1') OR Address=274 OR
|
|
Address=275 OR ((Address>=276 AND Address<=531)
|
|
AND PR_LOCK2((Address-276)/16)='1') OR Address=532
|
|
OR Address=533 OR ((Address>=534 AND Address<=767)
|
|
AND PR_LOCK3((Address-534)/16) = '1') THEN
|
|
PSTART <= '1', '0' AFTER 1 ns;
|
|
WIP := '1';
|
|
Addr := Address;
|
|
IF Viol /= '0' THEN
|
|
WOTPData := -1;
|
|
ELSE
|
|
WOTPData := WOTPByte;
|
|
END IF;
|
|
ELSIF (Address < 100 OR Address > 767 ) THEN
|
|
P_ERR := '1';
|
|
WEL := '0';
|
|
ELSE
|
|
WEL := '0';
|
|
END IF;
|
|
ELSIF Instruct = SE AND WEL = '1' THEN
|
|
sect := Address / 16#10000#;
|
|
IF Sec_Prot(sect) = '0' THEN
|
|
ESTART <= '1', '0' AFTER 1 ns;
|
|
WIP := '1';
|
|
Addr := Address;
|
|
ELSE
|
|
WEL := '0';
|
|
END IF;
|
|
ELSIF Instruct = BE AND WEL = '1' THEN
|
|
IF (BP0='0' AND BP1='0' AND BP2='0') THEN
|
|
ESTART <= '1', '0' AFTER 1 ns;
|
|
WIP := '1';
|
|
ELSE
|
|
WEL := '0';
|
|
END IF;
|
|
ELSIF Instruct = P4E AND WEL = '1' THEN
|
|
sect := Address / 16#10000#;
|
|
IF ((sect=0 OR sect=1) AND TBPARM='0')
|
|
OR ((sect=SecNum OR sect=SecNum-1)
|
|
AND TBPARM='1') THEN
|
|
IF Sec_Prot(sect) = '0' THEN
|
|
ESTART <= '1', '0' AFTER 1 ns;
|
|
WIP := '1';
|
|
Addr := Address;
|
|
ELSE
|
|
WEL := '0';
|
|
END IF;
|
|
ELSE
|
|
E_ERR := '1';
|
|
WEL := '0';
|
|
END IF;
|
|
ELSIF Instruct = P8E AND WEL = '1' THEN
|
|
sect := Address / 16#10000#;
|
|
IF ((sect=0 OR sect=1) AND TBPARM='0')
|
|
OR ((sect=SecNum OR sect=SecNum-1)
|
|
AND TBPARM='1') THEN
|
|
IF Sec_Prot(sect) = '0' THEN
|
|
ESTART <= '1', '0' AFTER 1 ns;
|
|
WIP := '1';
|
|
Addr := Address;
|
|
ELSE
|
|
WEL := '0';
|
|
END IF;
|
|
ELSE
|
|
E_ERR := '1';
|
|
WEL := '0';
|
|
END IF;
|
|
ELSIF Instruct = CLSR THEN
|
|
E_ERR := '0';
|
|
P_ERR := '0';
|
|
ELSIF Instruct = DP THEN
|
|
RES_in <= '0';
|
|
DP_in <= '1';
|
|
ELSIF Instruct = RES_READ_ES THEN
|
|
RES_in <= '1';
|
|
END IF;
|
|
|
|
ELSIF oe AND RES_in = '0' THEN
|
|
IF Instruct = RDSR THEN
|
|
--Read Status Register
|
|
SOut_zd <= Status_reg(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
ELSIF Instruct = RCR THEN
|
|
--Read Security Conf. Register
|
|
SOut_zd <= Sec_conf_reg(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
ELSIF Instruct = READ OR Instruct = FAST_READ THEN
|
|
--Read Memory array
|
|
IF Instruct = READ THEN
|
|
fast_rd <= false;
|
|
rd_jid <= false;
|
|
rd <= true;
|
|
END IF;
|
|
data_out := to_slv(Mem(read_addr),8);
|
|
SOut_zd <= data_out(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
IF read_addr = AddrRANGE THEN
|
|
read_addr := 0;
|
|
ELSE
|
|
read_addr := read_addr + 1;
|
|
END IF;
|
|
END IF;
|
|
ELSIF Instruct = DUAL_READ OR Instruct = DH_READ THEN
|
|
--Read Memory array
|
|
fast_rd <= false;
|
|
rd <= false;
|
|
rd_jid <= false;
|
|
dual <= true;
|
|
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 = QUAD_READ OR Instruct = QH_READ)
|
|
AND QUAD = '1' THEN
|
|
--Read Memory array
|
|
fast_rd <= false;
|
|
rd <= false;
|
|
rd_jid <= false;
|
|
dual <= true;
|
|
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 read_addr = AddrRANGE THEN
|
|
read_addr := 0;
|
|
ELSE
|
|
read_addr := read_addr + 1;
|
|
END IF;
|
|
END IF;
|
|
ELSIF Instruct = OTPR THEN
|
|
IF (read_addr>=OTPLoAddr) AND (read_addr<=OTPHiAddr)
|
|
THEN
|
|
--Read OTP Memory array
|
|
fast_rd <= true;
|
|
rd_jid <= false;
|
|
rd <= false;
|
|
data_out := to_slv(OTPMem(read_addr),8);
|
|
SOut_zd <= data_out(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
read_addr := read_addr + 1;
|
|
END IF;
|
|
ELSIF (read_addr > OTPHiAddr) THEN
|
|
--OTP Read operation will not wrap to the
|
|
--starting address after the OTP address is at
|
|
--its maximum or Read Password Protection Mode
|
|
--is selected; instead, the data beyond the
|
|
--maximum OTP address will be undefined.
|
|
SOut_zd <= 'U';
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
END IF;
|
|
ELSIF Instruct = RDID THEN
|
|
--Read Device ID
|
|
--can be terminated by driving CSNeg high
|
|
--at any time
|
|
fast_rd <= false;
|
|
rd_jid <= true;
|
|
rd <= false;
|
|
ident_out := to_slv(Manuf_ID,8) & to_slv(DeviceID,16) &
|
|
to_slv(ExtendedBytes,8) & to_slv(ReservedBytes,8) &
|
|
to_slv(ReservedBytes,8) & to_slv(ReservedBytes,8) &
|
|
CFI_array_tmp;
|
|
SOut_zd <= ident_out(647-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 648 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
ELSIF Instruct = READ_ID THEN
|
|
--Read Manufacturer and Device ID
|
|
IF read_addr MOD 2 = 0 THEN
|
|
data_out := to_slv(Manuf_ID,8);
|
|
SOut_zd <= data_out(7 - read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
read_addr := read_addr + 1;
|
|
END IF;
|
|
ELSE
|
|
data_out := to_slv(ES,8);
|
|
SOut_zd <= data_out(7 - read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
read_addr := 0;
|
|
END IF;
|
|
END IF;
|
|
END IF;
|
|
ELSIF oe AND RES_in = '1' THEN
|
|
SOut_zd <= 'X';
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
ASSERT false
|
|
REPORT InstancePath & partID & "Command results" &
|
|
" can be corrupted, a delay of tRES" &
|
|
" currently in progress."
|
|
SEVERITY WARNING;
|
|
END IF;
|
|
|
|
WHEN WRITE_SR =>
|
|
IF oe AND Instruct = RDSR THEN
|
|
--Read Status Register
|
|
SOut_zd <= Status_reg(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
END IF;
|
|
IF oe AND Instruct = RCR THEN
|
|
SOut_zd <= Sec_conf_reg(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
END IF;
|
|
|
|
IF WDONE = '1' THEN
|
|
WIP := '0';
|
|
WEL := '0';
|
|
SRWD := Status_reg_in(7);--MSB first
|
|
|
|
IF FREEZE='0' THEN
|
|
--The Freeze Bit, when set to 1, locks the current
|
|
--state of the BP2-0 bits in Status Register,
|
|
--the TBPROT and TBPARM bits in the Config Register
|
|
--As long as the FREEZE bit remains cleared to logic
|
|
--'0', the other bits of the Configuration register
|
|
--including FREEZE are writeable.
|
|
|
|
BP2 := Status_reg_in(4);
|
|
BP1 := Status_reg_in(3);
|
|
BP0 := Status_reg_in(2);
|
|
|
|
BP := BP2 & BP1 & BP0;
|
|
|
|
IF cfg_write = '1' THEN
|
|
|
|
FREEZE := Sec_conf_reg_in(0);--MSB first
|
|
|
|
IF TBPARM = '0' THEN
|
|
TBPARM := Sec_conf_reg_in(2);
|
|
END IF;
|
|
|
|
IF TBPROT = '0' THEN
|
|
TBPROT := Sec_conf_reg_in(5);
|
|
END IF;
|
|
|
|
QUAD := Sec_conf_reg_in(1);
|
|
|
|
IF BPNV = '0' THEN
|
|
BPNV := Sec_conf_reg_in(3);
|
|
END IF;
|
|
|
|
END IF;
|
|
|
|
change_BP <= '1', '0' AFTER 1 ns;
|
|
END IF;
|
|
|
|
END IF;
|
|
|
|
WHEN PAGE_PG =>
|
|
IF oe AND Instruct = RDSR THEN
|
|
--Read Status Register
|
|
SOut_zd <= Status_reg(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
END IF;
|
|
IF oe AND Instruct = RCR THEN
|
|
SOut_zd <= Sec_conf_reg(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
END IF;
|
|
|
|
ADDRHILO_PG(AddrLo, AddrHi, Addr);
|
|
cnt := 0;
|
|
|
|
FOR i IN 0 TO wr_cnt LOOP
|
|
new_int := WData(i);
|
|
old_int := Mem(Addr + i - cnt);
|
|
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;
|
|
|
|
Mem(Addr + i - cnt) := -1;
|
|
|
|
IF (Addr + i) = AddrHi THEN
|
|
Addr := AddrLo;
|
|
cnt := i + 1;
|
|
END IF;
|
|
END LOOP;
|
|
cnt :=0;
|
|
IF PDONE = '1' THEN
|
|
WIP := '0';
|
|
WEL := '0';
|
|
FOR i IN 0 TO wr_cnt LOOP
|
|
Mem(Addr_tmp + i - cnt) := WData(i);
|
|
IF (Addr_tmp + i) = AddrHi THEN
|
|
Addr_tmp := AddrLo;
|
|
cnt := i + 1;
|
|
END IF;
|
|
END LOOP;
|
|
END IF;
|
|
|
|
WHEN OTP_PG =>
|
|
IF oe AND Instruct = RDSR THEN
|
|
--Read Status Register
|
|
SOut_zd <= Status_reg(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
END IF;
|
|
IF oe AND Instruct = RCR THEN
|
|
SOut_zd <= Sec_conf_reg(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
END IF;
|
|
|
|
new_int := WOTPData;
|
|
old_int := OTPMem(Addr);
|
|
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;
|
|
WOTPData := new_int;
|
|
ELSE
|
|
WOTPData := -1;
|
|
END IF;
|
|
OTPMem(Addr) := -1;
|
|
IF PDONE = '1' THEN
|
|
WIP := '0';
|
|
WEL := '0';
|
|
OTPMem(Addr) := WOTPData;
|
|
PR_LOCK1 := to_slv(OTPMem(257),8) & to_slv(OTPMem(256),8);
|
|
PR_LOCK2 := to_slv(OTPMem(275),8) & to_slv(OTPMem(274),8);
|
|
PR_LOCK3 := to_slv(OTPMem(533),8) & to_slv(OTPMem(532),8);
|
|
END IF;
|
|
|
|
WHEN SECTOR_ER =>
|
|
IF oe AND Instruct = RDSR THEN
|
|
--Read Status Register
|
|
SOut_zd <= Status_reg(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
END IF;
|
|
IF oe AND Instruct = RCR THEN
|
|
SOut_zd <= Sec_conf_reg(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
END IF;
|
|
|
|
ADDRHILO_SEC(AddrLo, AddrHi, Addr);
|
|
FOR i IN AddrLo TO AddrHi LOOP
|
|
Mem(i) := -1;
|
|
END LOOP;
|
|
IF EDONE = '1' THEN
|
|
WIP := '0';
|
|
WEL := '0';
|
|
FOR i IN AddrLo TO AddrHi LOOP
|
|
Mem(i) := MaxData;
|
|
END LOOP;
|
|
END IF;
|
|
|
|
WHEN BULK_ER =>
|
|
IF oe AND Instruct = RDSR THEN
|
|
--Read Status Register
|
|
SOut_zd <= Status_reg(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
END IF;
|
|
IF oe AND Instruct = RCR THEN
|
|
SOut_zd <= Sec_conf_reg(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
END IF;
|
|
FOR i IN 0 TO AddrRANGE LOOP
|
|
Mem(i) := -1;
|
|
END LOOP;
|
|
IF EDONE = '1' THEN
|
|
WIP := '0';
|
|
WEL := '0';
|
|
FOR i IN 0 TO AddrRANGE LOOP
|
|
Mem(i) := MaxData;
|
|
END LOOP;
|
|
END IF;
|
|
|
|
WHEN P4_ER =>
|
|
IF oe AND Instruct = RDSR THEN
|
|
--Read Status Register
|
|
SOut_zd <= Status_reg(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
END IF;
|
|
IF oe AND Instruct = RCR THEN
|
|
SOut_zd <= Sec_conf_reg(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
END IF;
|
|
ADDRHILO_PB4(AddrLo, AddrHi, Addr);
|
|
FOR i IN AddrLo TO AddrHi LOOP
|
|
Mem(i) := -1;
|
|
END LOOP;
|
|
IF EDONE = '1' THEN
|
|
WIP := '0';
|
|
WEL := '0';
|
|
FOR i IN AddrLo TO AddrHi LOOP
|
|
Mem(i) := MaxData;
|
|
END LOOP;
|
|
END IF;
|
|
|
|
WHEN P8_ER =>
|
|
IF oe AND Instruct = RDSR THEN
|
|
--Read Status Register
|
|
SOut_zd <= Status_reg(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
END IF;
|
|
IF oe AND Instruct = RCR THEN
|
|
SOut_zd <= Sec_conf_reg(7-read_cnt);
|
|
read_cnt := read_cnt + 1;
|
|
IF read_cnt = 8 THEN
|
|
read_cnt := 0;
|
|
END IF;
|
|
END IF;
|
|
ADDRHILO_PB8(AddrLo, AddrHi, Addr);
|
|
FOR i IN AddrLo TO AddrHi LOOP
|
|
Mem(i) := -1;
|
|
END LOOP;
|
|
IF EDONE = '1' THEN
|
|
WIP := '0';
|
|
WEL := '0';
|
|
FOR i IN AddrLo TO AddrHi LOOP
|
|
Mem(i) := MaxData;
|
|
END LOOP;
|
|
END IF;
|
|
|
|
WHEN DP_DOWN_WAIT =>
|
|
IF rising_edge(DP_out) THEN
|
|
DP_in <= '0';
|
|
ELSIF DP_in = '1' AND Instruct'EVENT THEN
|
|
ASSERT false
|
|
REPORT InstancePath & partID & "Command results" &
|
|
" can be corrupted, a delay of tPD" &
|
|
" currently in progress."
|
|
SEVERITY WARNING;
|
|
END IF;
|
|
|
|
WHEN DP_DOWN =>
|
|
IF falling_edge(write) THEN
|
|
IF Instruct = RES_READ_ES THEN
|
|
RES_in <= '1';
|
|
END IF;
|
|
ELSIF oe AND Instruct = RES_READ_ES THEN
|
|
--Read Electronic Signature
|
|
data_out := to_slv(ES,8);
|
|
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 CASE;
|
|
|
|
--Output Disable Control
|
|
IF (CSNeg_ipd = '1') THEN
|
|
SIOut_zd <= 'Z';
|
|
HOLDNegOut_zd <= 'Z';
|
|
WPNegOut_zd <= 'Z';
|
|
SOut_zd <= 'Z';
|
|
END IF;
|
|
|
|
IF NOW = 0 ns THEN
|
|
CFI_array(16#07#) := 16#FF#;
|
|
CFI_array(16#08#) := 16#FF#;
|
|
CFI_array(16#09#) := 16#FF#;
|
|
CFI_array(16#0A#) := 16#FF#;
|
|
CFI_array(16#0B#) := 16#FF#;
|
|
CFI_array(16#0C#) := 16#FF#;
|
|
CFI_array(16#0D#) := 16#FF#;
|
|
CFI_array(16#0E#) := 16#FF#;
|
|
CFI_array(16#0F#) := 16#FF#;
|
|
--Product Group CFI Query Identification String
|
|
CFI_array(16#10#) := 16#51#;
|
|
CFI_array(16#11#) := 16#52#;
|
|
CFI_array(16#12#) := 16#59#;
|
|
CFI_array(16#13#) := 16#02#;
|
|
CFI_array(16#14#) := 16#00#;
|
|
CFI_array(16#15#) := 16#40#;
|
|
CFI_array(16#16#) := 16#00#;
|
|
CFI_array(16#17#) := 16#00#;
|
|
CFI_array(16#18#) := 16#00#;
|
|
CFI_array(16#19#) := 16#00#;
|
|
CFI_array(16#1A#) := 16#00#;
|
|
--Product Group CFI system interface string
|
|
CFI_array(16#1B#) := 16#27#;
|
|
CFI_array(16#1C#) := 16#36#;
|
|
CFI_array(16#1D#) := 16#00#;
|
|
CFI_array(16#1E#) := 16#00#;
|
|
CFI_array(16#1F#) := 16#0B#;
|
|
CFI_array(16#20#) := 16#0B#;
|
|
CFI_array(16#21#) := 16#09#;
|
|
CFI_array(16#22#) := 16#0F#;
|
|
CFI_array(16#23#) := 16#01#;
|
|
CFI_array(16#24#) := 16#01#;
|
|
CFI_array(16#25#) := 16#02#;
|
|
CFI_array(16#26#) := 16#01#;
|
|
--Product Group CFI Device Geometry Definition
|
|
CFI_array(16#27#) := 16#16#;
|
|
CFI_array(16#28#) := 16#05#;
|
|
CFI_array(16#29#) := 16#05#;
|
|
CFI_array(16#2A#) := 16#08#;
|
|
CFI_array(16#2B#) := 16#00#;
|
|
CFI_array(16#2C#) := 16#02#;
|
|
CFI_array(16#2D#) := 16#1F#;
|
|
CFI_array(16#2E#) := 16#00#;
|
|
CFI_array(16#2F#) := 16#10#;
|
|
CFI_array(16#30#) := 16#00#;
|
|
CFI_array(16#31#) := 16#3D#;
|
|
CFI_array(16#32#) := 16#00#;
|
|
CFI_array(16#33#) := 16#00#;
|
|
CFI_array(16#34#) := 16#01#;
|
|
CFI_array(16#35#) := 16#00#;
|
|
CFI_array(16#36#) := 16#00#;
|
|
CFI_array(16#37#) := 16#00#;
|
|
CFI_array(16#38#) := 16#00#;
|
|
CFI_array(16#39#) := 16#00#;
|
|
CFI_array(16#3A#) := 16#00#;
|
|
CFI_array(16#3B#) := 16#00#;
|
|
CFI_array(16#3C#) := 16#00#;
|
|
CFI_array(16#3D#) := 16#FF#;
|
|
CFI_array(16#3E#) := 16#FF#;
|
|
CFI_array(16#3F#) := 16#FF#;
|
|
--Product Group CFI Primary Vendor-Specific Extended Query
|
|
CFI_array(16#40#) := 16#50#;
|
|
CFI_array(16#41#) := 16#52#;
|
|
CFI_array(16#42#) := 16#49#;
|
|
CFI_array(16#43#) := 16#31#;
|
|
CFI_array(16#44#) := 16#33#;
|
|
CFI_array(16#45#) := 16#15#;
|
|
CFI_array(16#46#) := 16#00#;
|
|
CFI_array(16#47#) := 16#01#;
|
|
CFI_array(16#48#) := 16#00#;
|
|
CFI_array(16#49#) := 16#05#;
|
|
CFI_array(16#4A#) := 16#00#;
|
|
CFI_array(16#4B#) := 16#01#;
|
|
CFI_array(16#4C#) := 16#03#;
|
|
CFI_array(16#4D#) := 16#85#;
|
|
CFI_array(16#4E#) := 16#95#;
|
|
CFI_array(16#4F#) := 16#07#;
|
|
CFI_array(16#50#) := 16#00#;
|
|
END IF;
|
|
|
|
CFI_array_tmp :=to_slv(CFI_array(16#07#), 8) &
|
|
to_slv(CFI_array(16#08#), 8) &
|
|
to_slv(CFI_array(16#09#), 8) &
|
|
to_slv(CFI_array(16#0A#), 8) &
|
|
to_slv(CFI_array(16#0B#), 8) &
|
|
to_slv(CFI_array(16#0C#), 8) &
|
|
to_slv(CFI_array(16#0D#), 8) &
|
|
to_slv(CFI_array(16#0E#), 8) &
|
|
to_slv(CFI_array(16#0F#), 8) &
|
|
to_slv(CFI_array(16#10#), 8) &
|
|
to_slv(CFI_array(16#11#), 8) &
|
|
to_slv(CFI_array(16#12#), 8) &
|
|
to_slv(CFI_array(16#13#), 8) &
|
|
to_slv(CFI_array(16#14#), 8) &
|
|
to_slv(CFI_array(16#15#), 8) &
|
|
to_slv(CFI_array(16#16#), 8) &
|
|
to_slv(CFI_array(16#17#), 8) &
|
|
to_slv(CFI_array(16#18#), 8) &
|
|
to_slv(CFI_array(16#19#), 8) &
|
|
to_slv(CFI_array(16#1A#), 8) &
|
|
to_slv(CFI_array(16#1B#), 8) &
|
|
to_slv(CFI_array(16#1C#), 8) &
|
|
to_slv(CFI_array(16#1D#), 8) &
|
|
to_slv(CFI_array(16#1E#), 8) &
|
|
to_slv(CFI_array(16#1F#), 8) &
|
|
to_slv(CFI_array(16#20#), 8) &
|
|
to_slv(CFI_array(16#21#), 8) &
|
|
to_slv(CFI_array(16#22#), 8) &
|
|
to_slv(CFI_array(16#23#), 8) &
|
|
to_slv(CFI_array(16#24#), 8) &
|
|
to_slv(CFI_array(16#25#), 8) &
|
|
to_slv(CFI_array(16#26#), 8) &
|
|
to_slv(CFI_array(16#27#), 8) &
|
|
to_slv(CFI_array(16#28#), 8) &
|
|
to_slv(CFI_array(16#29#), 8) &
|
|
to_slv(CFI_array(16#2A#), 8) &
|
|
to_slv(CFI_array(16#2B#), 8) &
|
|
to_slv(CFI_array(16#2C#), 8) &
|
|
to_slv(CFI_array(16#2D#), 8) &
|
|
to_slv(CFI_array(16#2E#), 8) &
|
|
to_slv(CFI_array(16#2F#), 8) &
|
|
to_slv(CFI_array(16#30#), 8) &
|
|
to_slv(CFI_array(16#31#), 8) &
|
|
to_slv(CFI_array(16#32#), 8) &
|
|
to_slv(CFI_array(16#33#), 8) &
|
|
to_slv(CFI_array(16#34#), 8) &
|
|
to_slv(CFI_array(16#35#), 8) &
|
|
to_slv(CFI_array(16#36#), 8) &
|
|
to_slv(CFI_array(16#37#), 8) &
|
|
to_slv(CFI_array(16#38#), 8) &
|
|
to_slv(CFI_array(16#39#), 8) &
|
|
to_slv(CFI_array(16#3A#), 8) &
|
|
to_slv(CFI_array(16#3B#), 8) &
|
|
to_slv(CFI_array(16#3C#), 8) &
|
|
to_slv(CFI_array(16#3D#), 8) &
|
|
to_slv(CFI_array(16#3E#), 8) &
|
|
to_slv(CFI_array(16#3F#), 8) &
|
|
to_slv(CFI_array(16#40#), 8) &
|
|
to_slv(CFI_array(16#41#), 8) &
|
|
to_slv(CFI_array(16#42#), 8) &
|
|
to_slv(CFI_array(16#43#), 8) &
|
|
to_slv(CFI_array(16#44#), 8) &
|
|
to_slv(CFI_array(16#45#), 8) &
|
|
to_slv(CFI_array(16#46#), 8) &
|
|
to_slv(CFI_array(16#47#), 8) &
|
|
to_slv(CFI_array(16#48#), 8) &
|
|
to_slv(CFI_array(16#49#), 8) &
|
|
to_slv(CFI_array(16#4A#), 8) &
|
|
to_slv(CFI_array(16#4B#), 8) &
|
|
to_slv(CFI_array(16#4C#), 8) &
|
|
to_slv(CFI_array(16#4D#), 8) &
|
|
to_slv(CFI_array(16#4E#), 8) &
|
|
to_slv(CFI_array(16#4F#), 8) &
|
|
to_slv(CFI_array(16#50#), 8);
|
|
|
|
END PROCESS Functional;
|
|
|
|
Protect : PROCESS(change_BP)
|
|
BEGIN
|
|
IF rising_edge(change_BP) THEN
|
|
|
|
CASE BP IS
|
|
WHEN "000" =>
|
|
Sec_Prot := (others => '0');
|
|
WHEN "001" =>
|
|
IF TBPROT = '0' THEN
|
|
Sec_Prot(63 downto 63) := (others => '1');
|
|
Sec_Prot(62 downto 0) := (others => '0');
|
|
ELSE
|
|
Sec_Prot(0 downto 0) := (others => '1');
|
|
Sec_Prot(63 downto 1) := (others => '0');
|
|
END IF;
|
|
WHEN "010" =>
|
|
IF TBPROT = '0' THEN
|
|
Sec_Prot(63 downto 62) := (others => '1');
|
|
Sec_Prot(61 downto 0) := (others => '0');
|
|
ELSE
|
|
Sec_Prot(1 downto 0) := (others => '1');
|
|
Sec_Prot(63 downto 2) := (others => '0');
|
|
END IF;
|
|
WHEN "011" =>
|
|
IF TBPROT = '0' THEN
|
|
Sec_Prot(63 downto 60) := (others => '1');
|
|
Sec_Prot(59 downto 0) := (others => '0');
|
|
ELSE
|
|
Sec_Prot(3 downto 0) := (others => '1');
|
|
Sec_Prot(63 downto 4) := (others => '0');
|
|
END IF;
|
|
WHEN "100" =>
|
|
IF TBPROT = '0' THEN
|
|
Sec_Prot(63 downto 56) := (others => '1');
|
|
Sec_Prot(55 downto 0) := (others => '0');
|
|
ELSE
|
|
Sec_Prot(7 downto 0) := (others => '1');
|
|
Sec_Prot(63 downto 8) := (others => '0');
|
|
END IF;
|
|
WHEN "101" =>
|
|
IF TBPROT = '0' THEN
|
|
Sec_Prot(63 downto 48) := (others => '1');
|
|
Sec_Prot(47 downto 0) := (others => '0');
|
|
ELSE
|
|
Sec_Prot(15 downto 0) := (others => '1');
|
|
Sec_Prot(63 downto 16) := (others => '0');
|
|
END IF;
|
|
WHEN "110" =>
|
|
IF TBPROT = '0' THEN
|
|
Sec_Prot(63 downto 32) := (others => '1');
|
|
Sec_Prot(31 downto 0) := (others => '0');
|
|
ELSE
|
|
Sec_Prot(31 downto 0) := (others => '1');
|
|
Sec_Prot(63 downto 32) := (others => '0');
|
|
END IF;
|
|
WHEN OTHERS =>
|
|
Sec_Prot := (others => '1');
|
|
END CASE;
|
|
END IF;
|
|
END PROCESS Protect;
|
|
|
|
HOLD_FRAME_ON_PO_ZD : PROCESS(SOut_zd, SIOut_zd, HOLDNeg_pullup)
|
|
BEGIN
|
|
IF (HOLDNeg_pullup = '0' AND QUAD /= '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 (QUAD = '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 (QUAD = '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 otp_file : text is otp_file_name;
|
|
VARIABLE ind : NATURAL RANGE 0 TO AddrRANGE := 0;
|
|
VARIABLE secsi_ind : NATURAL RANGE 16#100# TO 16#2FF# := 16#100#;
|
|
VARIABLE buf : line;
|
|
|
|
BEGIN
|
|
---------------------------------------------------------------------------
|
|
--s25fl032p memory preload file format
|
|
-----------------------------------
|
|
---------------------------------------------------------------------------
|
|
-- / - comment
|
|
-- @aaaaaa - <aaaaaa> stands for address
|
|
-- dd - <dd> is byte to be written at Mem(aaaaaa++)
|
|
-- (aaaaaa is incremented at every load)
|
|
-- only first 1-7 columns are loaded. NO empty lines !!!!!!!!!!!!!!!!
|
|
---------------------------------------------------------------------------
|
|
|
|
-- memory preload
|
|
IF (mem_file_name /= "none" AND UserPreload) THEN
|
|
ind := 0;
|
|
Mem := (OTHERS => MaxData);
|
|
WHILE (not ENDFILE (mem_file)) LOOP
|
|
READLINE (mem_file, buf);
|
|
IF buf(1) = '/' THEN
|
|
NEXT;
|
|
ELSIF buf(1) = '@' THEN
|
|
IF ind > AddrRANGE THEN
|
|
ASSERT false
|
|
REPORT "Given preload address is out of" &
|
|
"memory address range"
|
|
SEVERITY warning;
|
|
ELSE
|
|
ind := h(buf(2 to 7)); --address
|
|
END IF;
|
|
ELSE
|
|
Mem(ind) := h(buf(1 to 2));
|
|
ind := ind + 1;
|
|
END IF;
|
|
END LOOP;
|
|
END IF;
|
|
|
|
---------------------------------------------------------------------------
|
|
--s25fl032p_otp memory preload file format
|
|
-----------------------------------
|
|
---------------------------------------------------------------------------
|
|
-- / - comment
|
|
-- @aaa - <aaa> stands for address
|
|
-- dd - <dd> is byte to be written at OTPMem(aaa++)
|
|
-- (aaa is incremented at every load)
|
|
-- only first 1-4 columns are loaded. NO empty lines !!!!!!!!!!!!!!!!
|
|
---------------------------------------------------------------------------
|
|
|
|
-- memory preload
|
|
IF (otp_file_name /= "none" AND UserPreload) THEN
|
|
secsi_ind := 16#100#;
|
|
OTPMem := (OTHERS => MaxData);
|
|
WHILE (not ENDFILE (otp_file)) LOOP
|
|
READLINE (otp_file, buf);
|
|
IF buf(1) = '/' THEN
|
|
NEXT;
|
|
ELSIF buf(1) = '@' THEN
|
|
IF secsi_ind > 16#2FF# OR secsi_ind < 16#100# THEN
|
|
ASSERT false
|
|
REPORT "Given preload address is out of" &
|
|
"OTP address range"
|
|
SEVERITY warning;
|
|
ELSE
|
|
secsi_ind := h(buf(2 to 4)); --address
|
|
END IF;
|
|
ELSE
|
|
OTPMem(secsi_ind) := h(buf(1 to 2));
|
|
PR_LOCK1 := to_slv(OTPMem(257),8) & to_slv(OTPMem(256),8);
|
|
PR_LOCK2 := to_slv(OTPMem(275),8) & to_slv(OTPMem(274),8);
|
|
PR_LOCK3 := to_slv(OTPMem(533),8) & to_slv(OTPMem(532),8);
|
|
secsi_ind := secsi_ind + 1;
|
|
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 => "PO",
|
|
OutTemp => SOut_z,
|
|
GlitchData => SO_GlitchData,
|
|
Paths => (
|
|
0 => (InputChangeTime => SCK_ipd'LAST_EVENT,
|
|
PathDelay => VitalExtendtofillDelay(tpd_SCK_SO),
|
|
PathCondition => SOut_z /= 'Z'
|
|
AND (NOT dual)),
|
|
1 => (InputChangeTime => SCK_ipd'LAST_EVENT,
|
|
PathDelay => VitalExtendtofillDelay(tpd_SCK_SI),
|
|
PathCondition => SOut_z /= 'Z'
|
|
AND dual),
|
|
2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT,
|
|
PathDelay => tpd_CSNeg_SO,
|
|
PathCondition => CSNeg_ipd = '1'),
|
|
3 => (InputChangeTime => HOLDNegIn'LAST_EVENT,
|
|
PathDelay => tpd_HOLDNeg_SO,
|
|
PathCondition => TRUE)
|
|
)
|
|
);
|
|
END PROCESS;
|
|
|
|
SI_Out_PathDelay : PROCESS(SIOut_z)
|
|
|
|
VARIABLE SI_GlitchData : VitalGlitchDataType;
|
|
BEGIN
|
|
VitalPathDelay01Z (
|
|
OutSignal => SIOut,
|
|
OutSignalName => "SI",
|
|
OutTemp => SIOut_z,
|
|
GlitchData => SI_GlitchData,
|
|
Paths => (
|
|
0 => (InputChangeTime => SCK_ipd'LAST_EVENT,
|
|
PathDelay => VitalExtendtofillDelay(tpd_SCK_SI),
|
|
PathCondition => SIOut_z /= 'Z' AND dual),
|
|
1 => (InputChangeTime => CSNeg_ipd'LAST_EVENT,
|
|
PathDelay => tpd_CSNeg_SO,
|
|
PathCondition => CSNeg_ipd = '1' AND dual),
|
|
2 => (InputChangeTime => HOLDNegIn'LAST_EVENT,
|
|
PathDelay => tpd_HOLDNeg_SO,
|
|
PathCondition => dual)
|
|
)
|
|
);
|
|
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_SI),
|
|
PathCondition => HOLDNegOut_zd /= 'Z' AND dual
|
|
AND QUAD = '1'),
|
|
1 => (InputChangeTime => CSNeg_ipd'LAST_EVENT,
|
|
PathDelay => tpd_CSNeg_SO,
|
|
PathCondition => CSNeg_ipd = '1' AND dual
|
|
AND QUAD = '1')
|
|
)
|
|
);
|
|
END PROCESS;
|
|
|
|
W_Out_PathDelay : PROCESS(WPNegOut_zd)
|
|
|
|
VARIABLE W_GlitchData : VitalGlitchDataType;
|
|
BEGIN
|
|
VitalPathDelay01Z (
|
|
OutSignal => WPNegOut,
|
|
OutSignalName => "WPNeg",
|
|
OutTemp => WPNegOut_zd,
|
|
GlitchData => W_GlitchData,
|
|
Paths => (
|
|
0 => (InputChangeTime => SCK_ipd'LAST_EVENT,
|
|
PathDelay => VitalExtendtofillDelay(tpd_SCK_SI),
|
|
PathCondition => HOLDNegOut_zd /= 'Z'AND dual
|
|
AND QUAD = '1'),
|
|
1 => (InputChangeTime => CSNeg_ipd'LAST_EVENT,
|
|
PathDelay => tpd_CSNeg_SO,
|
|
PathCondition => CSNeg_ipd = '1' AND dual
|
|
AND QUAD = '1')
|
|
)
|
|
);
|
|
END PROCESS;
|
|
END BLOCK behavior;
|
|
END vhdl_behavioral;
|