------------------------------------------------------------------------------ -- INTEL DEVELOPER'S SOFTWARE LICENSE AGREEMENT -- -- BY USING THIS SOFTWARE, YOU ARE AGREEING TO BE BOUND -- BY THE TERMS OF THIS AGREEMENT. DO NOT USE THE SOFTWARE -- UNTIL YOU HAVE CAREFULLY READ AND AGREED TO THE FOLLOWING -- TERMS AND CONDITIONS. IF YOU DO NOT AGREE TO THE TERMS -- OF THIS AGREEMENT, PROMPTLY RETURN THE SOFTWARE PACKAGE -- AND ANY ACCOMPANYING ITEMS. -- -- IF YOU USE THIS SOFTWARE, YOU WILL BE BOUND BY THE TERMS -- OF THIS AGREEMENT. -- -- LICENSE: Intel Corporation ("Intel") grants you -- the non-exclusive right to use the enclosed software -- program ("Software"). You will not use, copy, modify, -- display, rent, sell or transfer the Software or any portion -- thereof, except as provided in this Agreement. -- -- System OEM Developers may: -- 1. copy the Software purposes; -- 2. internally instalfor internal support, backup -- or archival l, use, display, or distribute -- Intel owned Software in object code format; -- 3. internally modify Software source code that -- Intel makes available to you for internal use -- only as an OEM Developer; -- 4. internally install, use, display, modify, distribute, -- and/or make derivatives ("Derivatives") of Intel owned -- Software ONLY if you are a System OEM Developer and -- NOT an end-user. -- -- RESTRICTIONS: -- -- YOU WILL NOT: -- 1. copy the Software, in whole or in part, except as -- provided for in this Agreement; -- 2. decompile or reverse engineer any Software provided -- in object code format; -- 3. distribute any Software or Derivative code to any -- end-users, unless approved by Intel in a prior writing. -- -- TRANSFER: You may not transfer the Software to any third -- party without Intel's prior written consent. -- -- OWNERSHIP AND COPYRIGHT OF SOFTWARE: Title to the Software -- and all copies thereof remain with Intel or its vendors. -- The Software is copyrighted and is protected by United States -- and international copyright laws. You will not remove the -- copyright notice from the Software. You agree to prevent -- any unauthorized copying of the Software. -- -- DERIVATIVE WORK: OEM Developers that make Derivatives will -- not be required to provide Intel with a copy of the source -- or object code. Any modification of Software shall be at -- your sole risk and expense. No Software or Derivative -- distribution to any third party is permitted under this -- Agreement. -- -- DUAL MEDIA SOFTWARE: If the Software package contains -- multiple media, you may only use the medium appropriate -- for your system. -- -- WARRANTY: Intel warrants that it has the right to license -- you to use, modify, display, or distribute the Software as -- provided in this Agreement. The Software is provided "AS IS" -- without WARRANTY of any kind. Intel makes no representations -- to upgrade, maintain, or support the Software at any time. -- -- -- THE ABOVE WARRANTIES ARE THE ONLY WARRANTIES OF ANY -- KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WARRANTIES -- OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE -- OR INFRINGEMENT OF ANY PATENT, COPYRIGHT OR OTHER -- INTELLECTUAL PROPERTY RIGHT. -- -- LIMITATION OF LIABILITY: NEITHER INTEL NOR ITS -- VENDORS OR AGENTS SHALL BE LIABLE FOR ANY LOSS -- OF PROFITS, LOSS OF USE, LOSS OF DATA, INTERRUPTION -- OF BUSINESS, NOR FOR INDIRECT, SPECIAL, INCIDENTAL -- OR CONSEQUENTIAL DAMAGES OF ANY KIND WHETHER UNDER -- THIS AGREEMENT OR OTHERWISE, EVEN IF ADVISED OF THE -- POSSIBILITY OF SUCH DAMAGES. -- -- TERMINATION OF THIS LICENSE: Intel reserves the right -- to conduct or have conducted audits to verify your -- compliance with this Agreement. Intel may terminate -- this Agreement at any time if you are in breach of -- any of its terms and conditions. Upon termination, -- you will immediately destroy, and certify in writing -- the destruction of, the Software or return all copies -- of the Software and documentation to Intel. -- -- U.S. GOVERNMENT RESTRICTED RIGHTS: The Software and -- documentation were developed at private expense and -- are provided with "RESTRICTED RIGHTS". Use, duplication -- or disclosure by the Government is subject to restrictions -- as set forth in FAR52.227-14 and DFAR252.227-7013 et seq. -- or its successor. -- -- EXPORT LAWS: You agree that the distribution and -- export/re-export of the Software is in compliance -- with the laws, regulations, orders or other restrictions -- of the U.S. Export Administration Regulations. -- -- APPLICABLE LAW: This Agreement is governed by the -- laws of the State of California and the United States, -- including patent and copyright laws. Any claim -- arising out of this Agreement will be brought in -- Santa Clara County, California. -- -- Copyright 1996, Intel Corporation, All Rights Reserved ------------------------------------------------------------------------------ -- Copyright 1997, Intel Corporation -- Functionality and specifications based on Smart 3 Burst Flash Memory -- specifications rev 0.0 (reference FM-0963) -- Refer to Intel Document Control for specifications. -- Intel Fast Boot Block 28F160F3 T120 -- Release History -- -- Date Rev Comments -- 4/12/98 1.0 Modified WAIT# pin logic -- 4/21/98 1.1 Modified MaxAddrLine references -- 6/04/98 1.2 Modified BurstCount incrementation (noted within code) -- 6/16/98 1.3 Updated timing specifications and open drain waitb pin -- per document 290644-001 -- 7/15/98 1.4 Add code to correct behavior in synchronous mode. -- 9/28/98 1.5 Memory loader now loads FFh into memory array -- Modified alias bit check on frequency and DOC from RCR -- Sync mode now bursts data when ADVb remains low -- Model now latches address on rising edge of ADVb or selected Clock edge -- Async mode will now burst data properly with ADVb low (Spec Update 297939-002) -- WAITb now operates per specification -- Clean up code --10/20/98 1.6 Add variable 'delayval' to correct improper function of one clock delays -- Correct condition where ADVb latch caused incorrect clock wait cycle. library ieee; use std.textio.all; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; ----------------------------------- entity fast_boot_block is port ( dq : inout std_logic_vector(15 downto 0); addr : in std_logic_vector(19 downto 0); clk : in bit; wpb : in bit; ceb : in bit; rpb : in bit; oeb : in bit; web : in bit; advb : in bit; waitb : out std_ulogic; vpp : in real; vcc : in real; vccq : in real ); end fast_boot_block; architecture behavior of fast_boot_block is -- These define the size of the device. -- MaxAddrLine is the number of the highest-order address line, when the byte-order line -- is numbered A0. A20, then, is the MaxAddrLine for a 16-meg device. -- -- CONSTANT MaxAddrLine : INTEGER := 19; -- 8 megabit -- The real MaxAddrLine for the 16-meg part is below. It is commented out to allow us to simulate a -- smaller part, so our simulation runs faster. CONSTANT MaxAddrLine : INTEGER := 20; -- Note - this is obviously size-related CONSTANT length : INTEGER := (2**(MaxAddrLine) - 1); -- These commands form the Intel Standard Command Set / Basic Command Set. CONSTANT ClearSRCmd : INTEGER := 16#50# ; CONSTANT EraseSingleBlockCmd : INTEGER := 16#20# ; CONSTANT ProgramCmd : INTEGER := 16#10# ; CONSTANT Program2Cmd : INTEGER := 16#40# ; CONSTANT ReadArrayCmd : INTEGER := 16#FF# ; CONSTANT ReadCSRCmd : INTEGER := 16#70# ; CONSTANT ReadIDCmd : INTEGER := 16#90# ; CONSTANT ResumeCmd : INTEGER := 16#D0# ; CONSTANT ConfirmCmd : INTEGER := 16#D0# ; CONSTANT SuspendCmd : INTEGER := 16#B0# ; -- This command is specific to the burst flash device. CONSTANT ReadCfgCmd : INTEGER := 16#60# ; CONSTANT ReadCfgCmd2 : INTEGER := 16#03# ; -- These are values for the ReadType variable. CONSTANT ReadArray : INTEGER := 1; CONSTANT ReadIDCodes : INTEGER := 2; CONSTANT ReadStatReg : INTEGER := 3; -- These are values for the WriteType variable. -- They are also used for the Running variable, which stores the type of operation currently -- occupying the device. CONSTANT WriteCmd : INTEGER := 0; CONSTANT WriteProgram : INTEGER := 1; CONSTANT WriteBlkErase : INTEGER := 2; CONSTANT SuspensionLatency : INTEGER := 8; -- Note: While SuspensionLatency isn't an operation or a valid value for WriteType, it is -- placed here because it is a valid value for the Running variable. When an operation is -- suspended, the device acts as it does when a program or erase is executed; the status -- register is placed on the bus during read cycles, and SR.7 is low -- until the suspension latency time is elapsed. CONSTANT ResetLatency : INTEGER := 9; CONSTANT WriteReadCfg : INTEGER := 10; -- These are the voltage ranges in the 3 volt spec (Fast_boot_block). CONSTANT Vcc3v10pcMin : REAL := 2.7; CONSTANT Vcc3v10pcMax : REAL := 3.6; CONSTANT Vcc3v5pcMin : REAL := 2.7; CONSTANT Vcc3v5pcMax : REAL := 2.85; CONSTANT Vpp5vLockout : REAL := 1.5; CONSTANT Vpp3vMin : REAL := 2.7; CONSTANT Vpp3vMax : REAL := 3.6; CONSTANT Vpp12vMin : REAL := 11.4; CONSTANT Vpp12vMax : REAL := 12.6; -- The timing specs shown below are for the EXTENDED temperature range. -- These specs are the 3V AC write specs. constant TZERO : time := 0 ns; constant TPHWL : time := 600 ns; constant TELWL : time := 0 ns; constant TWLEL : time := 0 ns; constant TWLWH : time := 75 ns; -- twp constant TELEH : time := 75 ns; -- twp constant TVLVH : time := 10 ns; constant TSHWH : time := 200 ns; -- Note - Fast_boot_block calls this tBHWH constant TVPWH : time := 200 ns; constant TAVWH : time := 75 ns; constant TVLEH : time := 75 ns; constant TDVWH : time := 70 ns; constant TWHDX : time := 0 ns; constant TWHAX : time := 0 ns; constant TEHAX : time := TWHAX; constant TEHDX : time := TWHDX; constant TWHEH : time := 0 ns; constant TEHWH : time := 0 ns; constant TWHWL : time := 20 ns; -- twph constant TEHEL : time := 20 ns; -- twph constant TWHGL : time := 0 ns; constant TQVVL : time := 0 ns; constant TQVSL : time := 0 ns; -- Note - Fast_boot_block calls this tQVBH constant TPHEL : time := TPHWL; constant TSHEH : time := TSHWH; constant TDVEH : time := TDVWH; constant TAVEH : time := TAVWH; constant TVPEH : time := TVPWH; constant TPLPH : time := 100 ns; constant TPLRH : time := 22 us; -- These are the values for state and new-state. They help us keep track of what's happening -- on the bus, and what sigs and transitions we're looking at. constant Powerup : integer := 0; constant OutputDisable : integer := 1; constant Powerdown : integer := 2; constant ReadCycleZ : integer := 3; constant ReadCycleXAsync : integer := 4; constant ReadCycleVAsync : integer := 5; constant WriteCycle : integer := 8; constant WEActive : integer := 9; constant ReadCycleXSync : integer := 10; constant ReadCycleVSync : integer := 11; -- This signal exists because it is convenient to view Vpp as a logic signal rather than a -- continuous variable to calculate Vpp setup and hold times. SIGNAL VppSig : STD_LOGIC; SIGNAL VccSig : STD_LOGIC; -- This signal exists to clock the main state machine. SIGNAL clock1 : bit := '0'; SIGNAL clock2 : bit := '1'; -- These aliases exist so we can distinguish events on the high-order portion of the address bus -- from events on the low-order portion. This is important when figuring out how long a read takes -- within a page versus without. CONSTANT pagelines : integer := 2; ALIAS addrhi : std_logic_vector((MaxAddrLine-1) downto Pagelines) IS addr ((MaxAddrLine-1) downto Pagelines); ALIAS addrlo : std_logic_vector(Pagelines - 1 downto 0) IS addr (Pagelines - 1 downto 0); -- This table exists to calculate the Intel burst offsets on the fly. TYPE BurstTableType IS ARRAY (0 TO 15, 0 TO 15) OF INTEGER; CONSTANT IntelBurst : BurstTableType := ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), (1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14), (2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13), (3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12), (4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11), (5, 4, 7, 6, 1, 0, 3, 2, 13, 12, 15, 14, 9, 8, 11, 10), (6, 7, 4, 5, 2, 3, 0, 1, 14, 15, 12, 13, 10, 11, 8, 9), (7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8), (8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7), (9, 8, 11, 10, 13, 12, 15, 14, 1, 0, 3, 2, 5, 4, 7, 6), (10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 5), (11, 10, 9, 8, 15, 14, 13, 12, 3, 2, 1, 0, 7, 6, 5, 4), (12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3), (13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2), (14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1), (15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)); --*************************************************************** --TYPE word IS ARRAY(15 downto 0) OF STD_ULOGIC; TYPE memarray IS ARRAY(0 TO length) OF std_ulogic_vector(15 DOWNTO 0) ; BEGIN MAIN:PROCESS(clock2,rpb,oeb,web,ceb,advb,addr,dq,vpp,clk) -- Scratchpad for converting STD_LOGIC_VECTOR to INTEGER VARIABLE adder : INTEGER := 0; VARIABLE twosum : INTEGER := 1; -- Integer copies of the latched data and the low byte of the latched data VARIABLE data : INTEGER; VARIABLE datalo : INTEGER; -- The entire memory VARIABLE memory :memarray; -- Scratchpad for the integer value of the block number of the latched address VARIABLE BlockNum : INTEGER; -- The Status Register goes here. VARIABLE SR :STD_LOGIC_VECTOR (7 downto 0) := "10000000"; -- The Read Config Register goes here. VARIABLE RCR : std_logic_vector (15 downto 0) := "1000100011000001"; -- These aliases are portions of the Read Config Register --(V1.5 changed FreqCfg +RCR ALIAS+ array from 14 downto 11 to 13 downto 11) ALIAS FreqCfg : std_logic_vector (2 downto 0) IS RCR(13 downto 11); --(V1.5 changed DataOutCfg +RCR ALIAS+ array from 10 downto 9 to 9 downto 9) ALIAS DataOutCfg : std_logic_vector (0 downto 0) IS RCR(9 downto 9); ALIAS BurstLen : std_logic_vector (2 downto 0) IS RCR(2 downto 0); -- This is used to keep track of what information the device will give on the next -- READ bus cycle. See the table in the constants section for examples. VARIABLE ReadType :INTEGER := ReadArray; -- This is used to keep track of what information the device expects to receive on -- the next WRITE bus cycle. See the table in the constants section for examples. VARIABLE WriteType :INTEGER := WriteCmd; -- This is used to store the state the main state machine of the model will enter at -- the next pseudo-clock (0.2 ns). VARIABLE next_state :INTEGER := 0; -- This stores the current state of the main state machine of the model. VARIABLE state:INTEGER := Powerup; -- Scratchpad to compare the value on the address bus to the latched address, to -- watch for transitions. Perhaps unnecessary. VARIABLE equal :BIT; -- One-timer used to initialize all the other variables. VARIABLE loader :BIT:= '0'; -- Latched data and address values go here VARIABLE hold_data : STD_ULOGIC_VECTOR(15 DOWNTO 0); VARIABLE hold_add : STD_ULOGIC_VECTOR (MaxAddrLine downto 0); VARIABLE adv_add : STD_ULOGIC_VECTOR (MaxAddrLine downto 0); -- This is a bit variable used to keep track of when read accesses will be processed at -- page-speed. VARIABLE paging : BIT := '0'; -- This is a variable which simulates the delay which can occur upon crossing a 16-word boundary -- during a continuous burst. VARIABLE delayclk : INTEGER := 0; VARIABLE delayval : INTEGER := 0; --(V16) -- These variables store the time of the last transition of the respective line -- to the respective state. This is necessary to verify pulse width timing -- requirements, those which measure the time between successive transitions of the -- same signal. VARIABLE timeWH : TIME := 0 ns; VARIABLE timeWL : TIME := 0 ns; VARIABLE timeEH : TIME := 0 ns; VARIABLE timeEL : TIME := 0 ns; VARIABLE timeSRValid : TIME := 0 ns; VARIABLE timeRPL : TIME := 0 ns; VARIABLE timeADVL : TIME := 0 ns; VARIABLE timeADVH : TIME := 0 ns; VARIABLE timeAddr : TIME := 0 ns; -- timeEdge is the time of the most recent important clock edge (that is, an edge upon which -- a transition should happen in synchronous burst mode. EdgeValid = 1 from when the edge is -- reached until the new data is placed on the bus, 0 anytime burst activity is being processed -- and 1 is inappropriate, and Z when no bursting is happening. VARIABLE timeEdge : TIME := 0 ns; VARIABLE EdgeValid : std_logic := 'Z'; -- This holds the WriteType constant of the operation currently busying the device. VARIABLE Running : INTEGER := 0; -- This holds the future time of the pending completion of the operation noted in -- Running. VARIABLE Completion : TIME := 0 ns; -- This variable holds the value of the SR when we move from ReadStateX to ReadStateV. -- This is important for compliance to spec, because it explicitly mentions that the SR is latched -- upon read, and is not refreshed until OE or CE transitions. VARIABLE SRLatch : STD_LOGIC_VECTOR (7 downto 0); -- These variables hold the block number of the block being erased, and the address of the word -- being programmed. If we attempt to read from either of these locations, we return Xes. VARIABLE ErasingBlk : INTEGER; VARIABLE ProgrammingAddr : INTEGER; -- These variables hold the information necessary to handle burst synchronous reads. VARIABLE WSCountdown : INTEGER; VARIABLE SyncAdder : INTEGER; VARIABLE EHCountdown : INTEGER; VARIABLE EHCFlag : INTEGER; VARIABLE BurstLength : INTEGER; VARIABLE BurstCount : INTEGER; VARIABLE BurstBaseAdder : INTEGER; VARIABLE BurstModAdder : INTEGER; -- These are flags to determine if a hold time error has been reported. Bad form to report -- the same error every billionth of a second. VARIABLE AddrHoldFlag : bit := '0'; VARIABLE DataHoldFlag : bit := '0'; VARIABLE VppHoldFlag : bit := '0'; VARIABLE WPHoldFlag : bit := '0'; VARIABLE VppMaintLFlag : bit := '0'; VARIABLE VppMaintSFlag : bit := '0'; VARIABLE VccMaintLFlag : bit := '0'; VARIABLE VccMaintSFlag : bit := '0'; -- These are the read timing specs. They became variables to allow multiple Vcc ranges in a given -- model. VARIABLE TAVQV : time; VARIABLE TELQV : time; VARIABLE TPHQV : time; VARIABLE TGLQV : time; VARIABLE TELQX : time; VARIABLE TEHQZ : time; VARIABLE TGLQX : time; VARIABLE TGHQZ : time; VARIABLE TOH : time; VARIABLE TELFL : time; VARIABLE TELFH : time; VARIABLE TFLQV : time; VARIABLE TFHQV : time; VARIABLE TFLQZ : time; VARIABLE TAVCH : time; VARIABLE TELCH : time; VARIABLE TVLCH : time; VARIABLE tCLK : time; VARIABLE tCH : time; VARIABLE tCHQV : time; VARIABLE tCHQX : time; VARIABLE tAPA : time; VARIABLE tAVVH : time; VARIABLE tELVH : time; VARIABLE tVLQV : time; VARIABLE tVLVH : time; VARIABLE tVHAX : time; VARIABLE tCHTH : time; VARIABLE tCHTL : time; -- These times are the latency times. They specify how long each operation leaves the -- device busy (as manifested by SR.7). Adding NOW to -- these times gives a time of completion in the future - comparing subsequent NOWs to -- that time will allow us to note when an operation finishes (and then update the Running, -- and SR.7 variables). VARIABLE W16_ProgWordWOBuffer : time; VARIABLE W16_ParmBlockErase : time; VARIABLE W16_MainBlockErase : time; VARIABLE W16_ProgSuspToRead : time; VARIABLE W16_EraseSuspToRead : time; -- Procedure CalcBlockNum - calculates BlockNumber associated with the address in the latch -- This is specific to the top boot subfamily PROCEDURE CalcBlockNum IS BEGIN BlockNum := 0; -- Figure the number of the twosum := 1; -- block to which the latched address FOR j IN 15 TO (MaxAddrLine - 1) LOOP -- corresponds, and store it in IF hold_add(j) = '1' THEN -- BlockNum BlockNum := BlockNum + twosum; END IF; twosum := twosum * 2; END LOOP; IF BlockNum = 2**(MaxAddrLine-15) - 1 THEN -- The address is in a parameter block. twosum := 1; FOR j IN 12 TO 14 LOOP IF hold_add(j) = '1' THEN BlockNum := BlockNum + twosum; END IF; twosum := twosum * 2; END LOOP; END IF; END CalcBlockNum; -- Procedure CalcAdder - calculates adder value associated with address in the latch PROCEDURE CalcAdder IS BEGIN adder := 0; -- This is generic code to take twosum := 1; -- the address in the latch FOR j IN 0 to (MaxAddrLine - 1) LOOP IF (hold_add(j) = '1') THEN -- and calculate adder := adder + twosum; -- the corresponding integer address END IF; -- value in adder. twosum := twosum * 2; -- Remember, hold_add is an array END LOOP; -- STD_ULOGIC. END CalcAdder; -- MAIN ROUTINE STARTS HERE! BEGIN -- This section intializes the memory array which contains all 1's. IF (loader = '0') THEN FOR i IN 0 TO length LOOP memory(i) := "1111111111111111"; --Test sequence only. To initialize memory with data --memory(i) := To_StdUlogicVector(conv_std_logic_vector(i,natural'(16))); END LOOP; SR := "10000000"; loader := '1'; END IF; -- Setup one-shot stuff ends here IF (addr'EVENT) AND (advb = '0') THEN timeAddr := NOW; END IF; --********************************************* --* ADV line processing starts here * --* ADV falling-edge processing * --********************************************* IF (advb = '0') AND (advb'EVENT) AND (advb'LAST_VALUE = '1') THEN --advb falling edge ASSERT ((NOW - timeADVH) >= tVLVH) REPORT "ADV Pulse Width violation (R17 - tVHVL)" SEVERITY ERROR; timeADVL := NOW; EdgeValid := 'Z'; EHCFlag := 1; --this flag used waitb sequence Set now for new burst cycle END IF; -- Code to update the address in the ADV latch (where appropriate) -- and to handle burst begin processing IF advb = '0' THEN FOR j IN (MaxAddrLine-1) DOWNTO 0 LOOP adv_add(j) := addr(j); END LOOP; IF RCR(15) = '0' AND EdgeValid = 'Z' THEN -- set up for new address latch sequence twosum := 1; WSCountdown := 0; FOR j IN 0 TO 2 LOOP --change (v15) loop from 3 to 2 IF FreqCfg(j) = '1' THEN WSCountdown := WSCountdown + twosum; END IF; twosum := twosum * 2; END LOOP; ASSERT((WSCountdown >= 1) AND (WSCountdown <= 6)) REPORT "Frequency Config out of defined range." SEVERITY ERROR; IF DataOutCfg(0) = '0' THEN --change (v15) EHCountdown := 0; ELSE EHCountdown := 1; END IF; hold_add := adv_add; CalcAdder; IF BurstLen = "001" THEN BurstLength := 4; ELSIF BurstLen = "010" THEN BurstLength := 8; ELSIF BurstLen = "111" THEN BurstLength := 99; ELSE ASSERT (0>1) REPORT "Invalid Burst Length" SEVERITY ERROR; END IF; IF (ReadType /= ReadArray) OR (adder >= (2**MaxAddrLine - 32768)) THEN BurstLength := 1; END IF; IF BurstLength = 99 THEN delayclk := WSCountdown - ((1 + EHCountdown) * (4 - (adder mod 4))); IF delayclk < 0 THEN delayclk := 0; END IF; delayval := delayclk; --(V16) END IF; EHCountdown := 0; BurstCount := 0; IF BurstLength /= 99 THEN BurstBaseAdder := adder - (adder mod BurstLength); BurstModAdder := adder mod BurstLength; ELSE BurstBaseAdder := adder; END IF; --(V15) Added sequence check below to check for valid latch sequence IF ((((clk = '0') AND (clk'EVENT) AND (clk'LAST_VALUE = '1') AND (RCR(6) = '0')) OR ((clk = '1') AND (clk'EVENT) AND (clk'LAST_VALUE = '0') AND (RCR(6) = '1'))) AND ((NOW - timeEdge) >= tVLCH)) THEN EdgeValid := '0'; --A clock edge latched data ASSERT ((NOW - timeEdge) >= tVLCH) REPORT "ADV low setup to CLK violation (R5 - tVLCH)" SEVERITY ERROR; ELSE EdgeValid := 'Z'; -- ADVb or CLK have not latched the data yet END IF; END IF; END IF; --******************************** --* ADV rising edge processing * --******************************** IF (advb = '1') AND (advb'EVENT) AND (advb'LAST_VALUE = '0') THEN -- advb has rising edge timeADVH := NOW; ASSERT (addr'LAST_EVENT >= tAVVH) REPORT "Address Setup to ADV high violation (R10 - tAVVH)" SEVERITY ERROR; ASSERT ((NOW - timeADVL) >= tVLVH) REPORT "ADV Pulse Width violation (R16 - tVLVH)" SEVERITY ERROR; ASSERT ((ceb /= '0') OR (ceb'LAST_EVENT >= tELVH)) REPORT "CE Low to ADV High Setup Time violation (R11 - tELVH)" SEVERITY ERROR; END IF; --Lets see if ADVb will latch the address during the start of a burst sequence (V15) IF (((advb = '1') AND (advb'EVENT) AND (advb'LAST_VALUE = '0')) AND -- advb has rising edge ((NOW - timeADVL) > tVLVH) AND (RCR(15) = '0' AND EdgeValid = 'Z' )) THEN EdgeValid := '0'; --ADVb rising edge latched data! WSCountdown := WSCountdown - 1; --advb latched, decrement WSCountdown once IF WSCountdown <0 THEN WSCountdown := 0; --(V16) END IF; END IF; -- ADV line processing ends here --************************** --* Clock Processing * --************************** IF (EdgeValid /= 'Z') THEN --Enter here with a valid address latched --Clock edge process starts IF ((clk = '0') AND (clk'EVENT) AND (clk'LAST_VALUE = '1') AND (RCR(6) = '0')) OR ((clk = '1') AND (clk'EVENT) AND (clk'LAST_VALUE = '0') AND (RCR(6) = '1')) THEN ASSERT (NOW - timeEdge >= tCLK) REPORT "Clock period violation (R1 - tCLK)" SEVERITY ERROR; ASSERT (NOW - clk'LAST_EVENT >= tCH) REPORT "Clock high(low) time violation (R2 - tCH(tCL))" SEVERITY ERROR; IF WSCountdown > 0 THEN WSCountdown := WSCountdown - 1; --Frequency config delay ELSIF EHCountdown > 0 THEN --DOC delay (as required) EHCountdown := EHCountdown - 1; ELSIF BurstLength = 99 AND delayclk > 0 AND SyncAdder mod 16 = 15 AND SyncAdder /= -1 THEN delayclk := delayclk - 1; IF delayclk = 0 THEN IF RCR(8) = '1' THEN waitb <= '1' AFTER tCHTH; END IF; END IF; ELSE IF RCR(8) = '0' THEN waitb <= '1' AFTER tCHTH; END IF; EdgeValid := '1'; timeEdge := NOW; BurstCount := BurstCount + 1; IF DataOutCfg(0) = '0' THEN EHCountdown := 0; ELSE EHCountdown := 1; END IF; ASSERT (EHCountdown /= 0) OR --two clocks ok ((EHCountdown = 0) AND ((WSCountdown <= 4) OR (BurstLength <= 4))) REPORT "Frequency configuration requires a DOC of 2 clocks." SEVERITY ERROR; END IF; --(v15) added EHCFlag to control waitb dropping on second clock if DOC is 1 --EHCFlag is set in the ADVb falling edge processing routine. IF BurstLength = 99 AND (delayclk > 0 OR delayval = 1) AND --(V16) ((SyncAdder mod 16 = 15 AND RCR(8) = '0') OR (SyncAdder mod 16 = 14 AND RCR(8) = '1')) AND ((DataOutCfg(0) = '1' AND EHCFlag = 0) OR --DOC 1, wait for second clk (DataOutCfg(0) = '0')) THEN --OK, go ahead and drop WAITb waitb <= '0' AFTER tCHTL; delayval := 0; --reset one time delayval(V16) ELSE IF BurstLength = 99 AND delayclk > 0 AND ((SyncAdder mod 16 = 15 AND RCR(8) = '0') OR (SyncAdder mod 16 = 14 AND RCR(8) = '1')) AND (DataOutCfg(0) = '1' AND EHCFlag = 1) THEN EHCFlag := EHCFlag - 1; END IF; END IF; ASSERT (NOW - timeADDR >= tAVCH) REPORT "Address Valid Setup to Clk violation (R4 - tAVCH)" SEVERITY ERROR; ASSERT (ceb = '1' OR ceb'LAST_EVENT >= tELCH) REPORT "CE Low setup to Clk violation (R5 -tELCH)" SEVERITY ERROR; ASSERT (advb = '1' OR advb'LAST_EVENT >= tVLCH) REPORT "ADV Low setup to Clk violation (R5 - tVLCH)" SEVERITY ERROR; END IF; -- Clock edge processing ends END IF; -- Power line processing begins here -- VppSig is high if Vpp is in the valid range IF ((Vpp > Vpp3vMin) AND (Vpp < Vpp3vMax)) THEN VppSig <= '1'; --Real and "Test" parameters are presented here. Test parameters are initialized to provide --faster simulation times as real values are too long to use practically in a VHDL model. W16_ProgWordWOBuffer := 23.5 us; -- tWHQV1 / tEHQV1 --W16_ParmBlockErase := 1 sec; -- tWHQV2 / tEHQV2 (Real) W16_ParmBlockErase := 10 us; -- tWHQV2 / tEHQV2 (Test) --W16_MainBlockErase := 1.8 sec; -- tWHQV2 / tEHQV2 (Real) W16_MainBlockErase := 10 us; -- tWHQV2 / tEHQV2 (Test) W16_ProgSuspToRead := 6 us; -- tWHRH1 / tEHRH1 W16_EraseSuspToRead := 13 us; -- tWHRH2 / tEHRH2 ELSIF ((Vpp > Vpp12vMin) AND (Vpp < Vpp12vMax)) THEN VppSig <= '1'; W16_ProgWordWOBuffer := 8 us; -- tWHQV1 / tEHQV1 --W16_ParmBlockErase := 0.8 sec; -- tWHQV2 / tEHQV2 (Real) W16_ParmBlockErase := 10 us; -- tWHQV2 / tEHQV2 (Test) --W16_MainBlockErase := 1.1 sec; -- tWHQV2 / tEHQV2 (Real) W16_MainBlockErase := 10 us; -- tWHQV2 / tEHQV2 (Test) W16_ProgSuspToRead := 5 us; -- tWHRH1 / tEHRH1 W16_EraseSuspToRead := 10 us; -- tWHRH2 / tEHRH2 ELSE VppSig <= '0'; END IF; -- VccSig is high if Vcc is in the valid range IF ((Vcc >= Vcc3v10pcMin) AND (Vcc <= Vcc3v10pcMax)) THEN VccSig <= '1'; tCLK := 15 ns; tCH := 2.5 ns; tAVCH := 7 ns; tELCH := 7 ns; tVLCH := 7 ns; tCHQV := 23 ns; tCHQX := 5 ns; tAVVH := 10 ns; tELVH := 10 ns; tAVQV := 120 ns; tELQV := 120 ns; tVLQV := 120 ns; tVLVH := 10 ns; tVHAX := 3 ns; tAPA := 30 ns; tGLQV := 30 ns; tPHQV := 600 ns; tELQX := 0 ns; tGLQX := 0 ns; tEHQZ := 25 ns; tGHQZ := 25 ns; tOH := 0 ns; tCHTL := 23 ns; tCHTH := 23 ns; ELSE VccSig <= '0'; END IF; -- Power line processing ends here -- THIS IS THE END of code which executes on every pass! -- NOW ENTERING the Big State Machine! -- One implicit assumption of the state machine is that no two control signals will -- transition within half a nanosecond of each other. It simplifies design greatly to -- assume that only one transition occurs during any given pseudo-clock. CASE state IS WHEN Powerup => -- This state corresponds to CE, WE, OE, and RP all high (inactive) dq <= "ZZZZZZZZZZZZZZZZ"; -- Outputs are off IF NOW > 0 ns THEN waitb <= 'H' after tCHTH; -- No sync delay END IF; IF (rpb = '0') THEN -- RP is asserted TimeRPL := NOW; -- Note when rpb went low next_state := Powerdown; -- Go to Powerdown ELSIF (ceb = '0') THEN -- CE is asserted timeEL := NOW; -- Note when ceb went low next_state := OutputDisable; -- Go to OutputDisable ELSIF (web = '0') THEN -- WE is asserted timeWL := NOW; -- Note when web went low next_state := WEActive; -- Go to WEActive ELSE next_state := Powerup; -- Nothing happened END IF; -- END STATE Powerup WHEN OutputDisable => -- This state has CE low/asserted, and WE, OE, and RP high/unasserted. -- From here, we can do a ReadCycle, a WriteCycle, a PowerDown, or -- even go back to PowerUp. IF (rpb = '0') THEN -- RP is asserted TimeRPL := NOW; -- note when RP went low next_state := Powerdown; -- Go to PowerDown ELSIF (ceb = '1') THEN -- CE is unasserted timeEH := NOW; -- Note when CE went high ASSERT (web'LAST_EVENT >= tWHEH) -- Check how long from WE REPORT "Enable Hold violation (tWHEH)." -- going high to CE going high SEVERITY ERROR; -- Enable Hold time next_state := Powerup; -- Return to Powerup ELSIF (oeb = '0') THEN -- OE is asserted - we're -- beginning a read cycle. next_state := ReadCycleZ; -- Go to ReadCycleZ state -- and wait for outputs to -- turn on ELSIF (web = '0') THEN -- WE is asserted - we're -- beginning a write cycle. timeWL := NOW; -- Note when WE went low ASSERT (ceb'LAST_EVENT >= tELWL) -- Verify that CE has been REPORT "Enable Setup violation (tELWL)" -- asserted long enough - SEVERITY ERROR; -- Enable Setup time ASSERT (rpb'LAST_EVENT >= tPHWL) -- Verify that RP has been REPORT "Powerdown Recovery Time violation (tPHWL)" -- unasserted long enough - SEVERITY ERROR; -- Powerdown Recovery time ASSERT (((NOW - web'LAST_EVENT) - timeWH) >= tWHWL) -- Verify that the WE line REPORT "WE Pulse High Time violation (tWHWL)" -- was high long enough - SEVERITY ERROR; -- WE Pulse High time next_state := WriteCycle; --Go to WriteCycle ELSE next_state := OutputDisable; --Nothing happened END IF; -- END STATE OutputDisable -- This state corresponds to WE# asserted (low), and OE# and CE# unasserted (high). -- The only reason to come here is to set up or leave a CE-controlled write. WHEN WEActive => -- WE# Asserted State - for CE-controlled writes IF (rpb = '0') THEN -- RP is asserted TimeRPL := NOW; -- note when rpb became asserted next_state := Powerdown; -- Goes to Powerdown ELSIF (web = '1') THEN -- WE is unasserted again -- Go back to Powerup timeWH := NOW; -- Note when web went high ASSERT (ceb'LAST_EVENT >= tEHWH) -- Verify there was enough time REPORT "Enable Hold violation (tEHWH)." -- from CE high to WE high - SEVERITY ERROR; -- Enable Hold time next_state := Powerup; -- Returns to powerup ELSIF (ceb = '0') THEN -- CE is asserted - about to -- do a WriteCycle timeEL := NOW; -- Note when CE went low ASSERT (web'LAST_EVENT >= tWLEL) -- Verify WE was low long enough REPORT "Enable Setup violation (tWLEL)" -- before CE went low - SEVERITY ERROR; -- Enable Setup time ASSERT (rpb'LAST_EVENT >= tPHEL) -- Verify RP was unasserted long REPORT "Powerdown Recovery Time violation (tPHEL)" -- enough before CE went low - SEVERITY ERROR; -- Powerdown Recovery time ASSERT (((NOW - ceb'LAST_EVENT) - timeEH) >= tEHEL) -- Verify CE was high long REPORT "CE Pulse High Time violation (tEHEL)" -- enough - CE Pulse Width High SEVERITY ERROR; next_state := WriteCycle; -- Goes to WriteCycle ELSE next_state := WEActive; -- Nothing happened END IF; -- END STATE WEActive WHEN ReadCycleZ => -- OE and CE either just became asserted or just became unasserted. -- We're in that portion of a read cycle right before the outputs -- turn on or right after they shut off DQ <= "ZZZZZZZZZZZZZZZZ"; -- All high-Z on the data outputs ASSERT (web'LAST_EVENT >= tWHGL) -- Verify that WE hasn't been asserted in REPORT "Violation of tWHGL (Write recovery before read)." SEVERITY ERROR; -- awhile - Write Recovery Before Read IF (rpb = '0') THEN -- rpb became asserted - go to Powerdown TimeRPL := NOW; -- note when rpb became asserted next_state := PowerDown; ELSIF ((ceb = '0' AND ceb'LAST_EVENT >= tELQX) AND -- If all the hold time requirements (oeb = '0' AND oeb'LAST_EVENT >= tGLQX)) THEN -- are met, turn on the outputs with SRLatch := SR; -- invalid data - go to a ReadCycleX IF RCR(15) = '0' THEN -- and latch the SR. next_state := ReadCycleXSync; ELSE next_state := ReadCycleXAsync; END IF; ELSIF (ceb = '1') THEN next_state := PowerUp; -- CE became unasserted somehow - -- go to Powerup ELSIF (oeb = '1') THEN next_state := OutputDisable; -- OE became unasserted - we're on -- the back edge of a read cycle. -- Go to OutputDisable ELSE next_state := ReadCycleZ; -- Nothing important happened - -- stay where we are. END IF; -- END STATE ReadCycleZ WHEN ReadCycleXAsync => -- This state corresponds to the two places on the read cycle timing diagram -- where the data is hatched to show that it isn't valid yet. Either we're -- just beginning a read, or we're just leaving it. From here, we go either -- to ReadCycleV, if the data's about to become valid, or to ReadCycleZ, if -- the outputs are about to shut off. DQ <= "XXXXXXXXXXXXXXXX"; -- Place all Xes on the outputs IF (rpb = '0') THEN -- rpb asserted - go to Powerdown state TimeRPL := NOW; next_state := PowerDown; -- If all the setup conditions are met, place valid data on the outputs and go to ReadCycleV ELSIF rpb'LAST_EVENT >= tPHQV AND (ceb = '0' AND ceb'LAST_EVENT >= tELQV) AND (oeb = '0' AND oeb'LAST_EVENT >= tGLQV) AND (((NOW - timeADVL) >= tVLQV) OR --V1.5 added ("NOW -...)" to condition (advb = '0' AND timeADVL = TZERO)) AND --V1.5 check advb is tied active for async ((paging = '0' AND addr'LAST_EVENT >= tAVQV) OR (paging = '1' AND addr'LAST_EVENT >= tAPA)) THEN hold_add := adv_add; -- Latch the address that's in the ADV latch -- we go to ReadCycleV, to check to see if -- it changes; if it does, the data goes -- invalid. next_state := ReadCycleVAsync; ELSIF ((oeb = '1' AND oeb'LAST_EVENT >= tGHQZ) -- If one of the control lines has gone high, OR (ceb = '1' AND -- go the other way - turn off the data bus, ceb'LAST_EVENT >= tEHQZ)) THEN -- and go to ReadCycleZ (after a certain lag next_state := ReadCycleZ; -- time) ELSE next_state := ReadCycleXAsync; -- Nothing happened. END IF; -- END STATE ReadCycleXAsync WHEN ReadCycleVAsync => -- This is the moment we've been waiting for - in ReadCycleV, -- all the setup conditions are finally met, and we place -- valid data on the data outputs. The only place to go from here -- is to ReadCycleX, when one of the control inputs changes -- (oeb, ceb, and addr all cause this) CalcAdder; CASE ReadType IS -- This case statement splits us into -- the different read modes. -- The value of ReadType is set -- through sending various commands -- to the device. WHEN ReadArray => -- Reading from the memory itself CalcBlockNum; IF BlockNum < (2**(MaxAddrLine-15) - 1) THEN paging := '1'; END IF; hold_data := memory(adder); -- Place the contents of the mem -- in a holding area IF (SR(6) = '1') AND BlockNum = ErasingBlk THEN -- If the read is in a block with hold_data := "XXXXXXXXXXXXXXXX"; -- erase suspended, the value's END IF; -- anyone's guess IF (SR(2) = '1') AND adder = ProgrammingAddr -- If there's a write suspended, THEN hold_data := "XXXXXXXXXXXXXXXX"; END IF; -- END ReadArray subcase -- Holding area's set up - we're done WHEN ReadIDCodes => -- Reading from the Device ID Codes IF (adder = 0) THEN hold_data := "0000000010001001"; -- $0089, Intel's MfrID ELSIF (adder = 1) THEN hold_data := "1000100011110011"; -- Fast_boot_block 16-meg Top boot ELSIF (adder = 16#00005#) THEN FOR j IN 15 DOWNTO 0 LOOP hold_data(j) := RCR(j); -- $00005 is home to the RCR, kinda END LOOP; ELSE hold_data := "XXXXXXXXXXXXXXXX"; -- Outside the known world. END IF; -- END ReadIDCodes subcase WHEN ReadStatReg => -- Reading the Status Register, -- regardless of the address FOR j IN 15 DOWNTO 8 LOOP -- Set the top byte of the holding hold_data(j) := '0'; -- area to $00 - the SR is a byte END LOOP; -- value, and the top byte is defined -- $00. FOR j IN 7 DOWNTO 0 LOOP -- If SR.7 = 1, then the data in the IF (j = 7) OR (SRLatch(7) = '1') THEN -- SR is valid, and we put it all in hold_data(j) := SRLatch(j); -- the holding area. If SR.7 = 0, ELSE hold_data(j) := 'X'; -- the SR is not valid (except for END IF; -- bit 7), and we set it to Xes. END LOOP; -- END ReadStatReg subcase WHEN OTHERS => -- If we get here, something went ASSERT (0>1) -- dramatically, horribly wrong. REPORT "Model failure - unknown ReadType" -- This simply can't happen. SEVERITY FAILURE; END CASE; -- WE HAVE NOW LEFT THE ReadType -- CASE STATEMENT! FOR j IN 15 DOWNTO 0 LOOP -- Put the stuff in the holding area dq(j) <= hold_data(j); -- onto the data outputs. END LOOP; equal := '1'; -- This is generic code to see if FOR j IN (MaxAddrLine-1) downto 0 LOOP -- the address in the adv latch has IF (hold_add(j) /= adv_add(j)) THEN -- changed from the one we latched equal := '0'; -- when we left ReadCycleX. If it END IF; -- has, equal will be 0. END LOOP; IF (rpb = '0') THEN -- RP is asserted. TimeRPL := NOW; -- Note when RP went low, next_state := PowerDown; -- and go to PowerDown. ELSIF ((oeb = '1' AND oeb'LAST_EVENT >= tOH) OR -- If one of the control lines has (ceb = '1' AND ceb'LAST_EVENT >= tOH) OR -- transitioned, or the address has (equal = '0' AND addr'LAST_EVENT >= tOH)) THEN -- changed, the data goes invalid next_state := ReadCycleXAsync; -- and we go to ReadCycleXAsync ELSE next_state := ReadCycleVAsync; -- Otherwise, stay here END IF; -- END STATE ReadCycleVAsync WHEN ReadCycleXSync => -- This state corresponds to the two places on the read cycle timing diagram -- where the data is hatched to show that it isn't valid yet. Either we're -- just beginning a read, or we're just leaving it. From here, we go either -- to ReadCycleV, if the data's about to become valid, or to ReadCycleZ, if -- the outputs are about to shut off. DQ <= "XXXXXXXXXXXXXXXX"; -- Place all Xes on the outputs IF (rpb = '0') THEN -- rpb asserted - go to Powerdown state TimeRPL := NOW; next_state := PowerDown; ELSIF (ceb = '0' AND ceb'LAST_EVENT >= tELQV) AND (oeb = '0' AND oeb'LAST_EVENT >= tGLQV) AND ((NOW >= (timeEdge + tCHQV)) AND EdgeValid = '1') THEN IF (RCR(7) = '0' AND BurstLength /= 99) THEN SyncAdder := BurstBaseAdder + IntelBurst(BurstModAdder, BurstCount - 1); ELSIF (RCR(7) = '1' AND BurstLength /= 99) THEN SyncAdder := BurstBaseAdder + ((BurstModAdder + BurstCount - 1) mod BurstLength); ELSE SyncAdder := BurstBaseAdder + BurstCount - 1; END IF; EdgeValid := '0'; IF ((BurstLength /= 99 AND BurstCount = BurstLength) OR (BurstLength = 99 AND SyncAdder = 2**(MaxAddrLine) - 32768)) THEN EdgeValid := 'Z'; END IF; next_state := ReadCycleVSync; ELSIF ((oeb = '1' AND oeb'LAST_EVENT >= tGHQZ) -- If one of the control lines has gone high, OR (ceb = '1' AND -- go the other way - turn off the data bus, ceb'LAST_EVENT >= tEHQZ)) THEN -- and go to ReadCycleZ (after a certain lag next_state := ReadCycleZ; -- time) ELSE next_state := ReadCycleXSync; -- Nothing happened. END IF; -- END STATE ReadCycleXSync WHEN ReadCycleVSync => -- This is the moment we've been waiting for - in ReadCycleV, -- all the setup conditions are finally met, and we place -- valid data on the data outputs. The only place to go from here -- is to ReadCycleX, when one of the control inputs changes -- (oeb, ceb, and addr all cause this) adder := SyncAdder; CASE ReadType IS -- This case statement splits us into -- the different read modes. -- The value of ReadType is set -- through sending various commands -- to the device. WHEN ReadArray => -- Reading from the memory itself CalcBlockNum; hold_data := memory(adder); -- Place the contents of the mem -- in a holding area IF (SR(6) = '1') AND BlockNum = ErasingBlk THEN -- If the read is in a block with hold_data := "XXXXXXXXXXXXXXXX"; -- erase suspended, the value's END IF; -- anyone's guess IF (SR(2) = '1') AND adder = ProgrammingAddr -- If there's a write suspended, THEN hold_data := "XXXXXXXXXXXXXXXX"; END IF; -- END ReadArray subcase -- Holding area's set up - we're done WHEN ReadIDCodes => -- Reading from the Device ID Codes IF (adder = 0) THEN hold_data := "0000000010001001"; -- $0089, Intel's MfrID ELSIF (adder = 1) THEN hold_data := "XXXXXXXXXXXXXXXX"; -- Device ID is currently unknown. ELSIF (adder = 16#07000#) THEN FOR j IN 15 DOWNTO 0 LOOP hold_data(j) := RCR(j); -- $07000 is home to the RCR, kinda END LOOP; ELSE hold_data := "XXXXXXXXXXXXXXXX"; -- Outside the known world. END IF; -- END ReadIDCodes subcase WHEN ReadStatReg => -- Reading the Status Register, -- regardless of the address FOR j IN 15 DOWNTO 8 LOOP -- Set the top byte of the holding hold_data(j) := '0'; -- area to $00 - the SR is a byte END LOOP; -- value, and the top byte is defined -- $00. FOR j IN 7 DOWNTO 0 LOOP -- If SR.7 = 1, then the data in the IF (j = 7) OR (SRLatch(7) = '1') THEN -- SR is valid, and we put it all in hold_data(j) := SRLatch(j); -- the holding area. If SR.7 = 0, ELSE hold_data(j) := 'X'; -- the SR is not valid (except for END IF; -- bit 7), and we set it to Xes. END LOOP; -- END ReadStatReg subcase WHEN OTHERS => -- If we get here, something went ASSERT (0>1) -- dramatically, horribly wrong. REPORT "Model failure - unknown ReadType" -- This simply can't happen. SEVERITY FAILURE; END CASE; -- WE HAVE NOW LEFT THE ReadType -- CASE STATEMENT! FOR j IN 15 DOWNTO 0 LOOP -- Put the stuff in the holding area dq(j) <= hold_data(j); -- onto the data outputs. END LOOP; IF (rpb = '0') THEN -- RP is asserted. TimeRPL := NOW; -- Note when RP went low, next_state := PowerDown; -- and go to PowerDown. ELSIF ((oeb = '1' AND oeb'LAST_EVENT >= tOH) OR -- If one of the control lines has (ceb = '1' AND ceb'LAST_EVENT >= tOH) OR -- transitioned, or the clock has (EdgeValid = '1' AND (NOW - timeEdge >= tCHQX)) OR (timeADVL = NOW)) -- presented the right edge a number THEN -- of times, the data goes invalid next_state := ReadCycleXSync; -- and we go to ReadCycleXSync ELSE next_state := ReadCycleVSync; -- Otherwise, stay here END IF; -- END STATE ReadCycleVSync WHEN WriteCycle => -- Unlike the read process, which goes through many substates, the -- write process only uses one monolithic state. To be here is to have -- WE and CE low/asserted, and OE and RP high/unasserted. Even then, the -- only interesting things happen on the rising edge of the controlling -- signal (usually WE, but not always.) waitb <= 'H' after tCHTH; -- In case of squirrels. IF (web = '1') THEN -- Rising edge, and by implication, -- a WE-controlled write. next_state := OutputDisable; -- Go to OutputDisable next timeWH := NOW; -- Note when WE went high ASSERT (((NOW - web'LAST_EVENT) - timeWL) >= tWLWH) REPORT "WE Pulse Width violation (tWLWH)." -- Make sure WE was low long enough SEVERITY ERROR; -- WE Pulse Width ASSERT ((wpb = '0') OR (wpb'LAST_EVENT >= tSHWH)) -- If WP is unasserted, make REPORT "WP High Setup violation (tSHWH)." -- sure it's been that way for tSHWH SEVERITY ERROR; -- WP setup to WE high ASSERT (dq'LAST_EVENT >= tDVWH) -- Check Data Setup time REPORT "Data setup time violation (tDVWH)." SEVERITY ERROR; ASSERT (addr'LAST_EVENT >= tAVWH) -- Check Address Setup time REPORT "Address setup time violation (tAVWH)." SEVERITY ERROR; ASSERT ((NOW - timeADVL) >= tVLEH) REPORT "ADV setup violation (W8 - tVLEH)" SEVERITY ERROR; ELSIF (ceb = '1') THEN -- Rising edge on CE - by implication -- a CE-controlled write next_state := WEActive; -- Go to WEActive next timeEH := NOW; -- Note when CE went high ASSERT (((NOW - ceb'LAST_EVENT) - timeEL) >= tELEH) REPORT "CE Pulse Width violation (tELEH)." -- Make sure CE was low long enough SEVERITY ERROR; -- CE Pulse Width ASSERT ((wpb = '0') OR (wpb'LAST_EVENT >= tSHEH)) -- If WP is unasserted, make REPORT "WP High Setup violation (tSHEH)." -- sure it's been that way for tSHEH SEVERITY ERROR; -- WP Setup to CE High ASSERT (dq'LAST_EVENT >= tDVEH) -- Check Data Setup time REPORT "Data setup time violation (tDVEH)." SEVERITY ERROR; ASSERT (addr'LAST_EVENT >= tAVEH) -- Check Address Setup time REPORT "Address setup time violation (tAVEH)." SEVERITY ERROR; ASSERT ((NOW - timeADVL) >= tVLEH) REPORT "ADV setup violation (W8 - tVLEH)" SEVERITY ERROR; END IF; -- End the if about control lines -- going back to high IF (rpb = '0') THEN -- RP is asserted. next_state := PowerDown; -- Go to Powerdown TimeRPL := NOW; -- and note when RP went low ELSIF (web = '1' OR ceb = '1') THEN -- If either of the control lines -- went high, we do all sorts of stuff hold_add := adv_add; FOR j IN 0 to 15 LOOP -- Latch the data when a line goes hold_data(j) := dq(j); -- high END LOOP; CalcAdder; data := 0; -- Integerize the data, and store datalo := 0; -- it in data, but also store the twosum := 1; -- low byte's integer value in datalo FOR j IN 0 to 15 LOOP IF (hold_data(j) = '1') THEN data := data + twosum; IF (j<8) THEN datalo := datalo + twosum; END IF; END IF; twosum := twosum * 2; END LOOP; CalcBlockNum; CASE WriteType IS -- The idea here's similar to the -- idea with the ReadType subcase. -- WriteType stores what sort of data -- the device expects to see on a -- write cycle. WHEN WriteCmd => -- Case 1 - The data's a command. CASE datalo IS -- On a command, the low byte holds -- the important stuff. WHEN ClearSRCmd => -- Got the command to clear the SR. IF ((running = 0) AND -- If the device isn't busy, and -- there isn't anything suspended, (SR(6) = '0' AND SR(2) = '0')) THEN SR := SR AND "11000101"; --Clear the status register. ELSE ASSERT(0>1) -- Otherwise, protest vigorously REPORT -- that the command wasn't valid. "Invalid Command While Device Busy (ClearSR)" SEVERITY ERROR; END IF; WHEN EraseSingleBlockCmd => -- Command to erase one block IF ((running = 0) AND -- If the device isn't busy, and -- there isn't anything suspended, (SR(6) = '0' AND SR(2) = '0')) THEN WriteType := WriteBlkErase; -- Go to WriteBlkErase mode -- and wait for confirmation. ELSE ASSERT(0>1) -- Otherwise, the command wasn't good REPORT "Invalid Command While Device Busy (EraseBlk)" SEVERITY ERROR; END IF; WHEN ProgramCmd => -- Command to program a byte/word. -- If the device isn't busy, and IF ((running = 0) AND (SR(2) = '0')) THEN -- no erase is suspended, WriteType := WriteProgram; -- Go to WriteProgram mode, -- and wait for the data byte/word. ELSE ASSERT(0>1) -- Otherwise... yeah. REPORT "Invalid Command While Device Busy (Program)" SEVERITY ERROR; END IF; WHEN Program2Cmd => -- Ditto the above - this is the -- alternate value for the same thing IF ((running = 0) AND (SR(2) = '0')) THEN WriteType := WriteProgram; ELSE ASSERT(0>1) REPORT "Invalid Command While Device Busy (Program)" SEVERITY ERROR; END IF; WHEN ReadArrayCmd => -- Command to change the read mode -- to read the memory array. IF (running = 0) THEN -- If nothing's running ReadType := ReadArray; -- Change the read mode ELSE ASSERT(0>1) -- Otherwise, no dice. REPORT "Invalid Command While Device Busy (ReadArray)" SEVERITY ERROR; END IF; WHEN ReadCSRCmd => -- Command to change the read mode -- to read the Status Register IF (running = 0) THEN -- If nothing's running ReadType := ReadStatReg; -- change the read mode ELSE ASSERT(0>1) -- Otherwise, complain. REPORT "Invalid Command While Device Busy (ReadSR)" SEVERITY ERROR; END IF; WHEN ReadIDCmd => -- Command to change the read mode -- to read the ID Codes IF ((running = 0) AND -- If nothing's running, and -- nothing's suspended, (SR(6) = '0' AND SR(2) = '0')) THEN ReadType := ReadIDCodes; -- change the read mode. ELSE ASSERT(0>1) -- Otherwise, gripe. REPORT "Invalid Command While Device Busy (ReadIDCodes)" SEVERITY ERROR; END IF; WHEN ReadCfgCmd => -- Command to set the Read Config -- Register IF ((running = 0) AND (SR(6) = '0' AND SR(2) = '0')) THEN WriteType := WriteReadCfg; ELSE ASSERT (0>1) REPORT "Invalid Command While Dev Busy (ReadConfig)" SEVERITY ERROR; END IF; WHEN ResumeCmd => -- Command to resume a suspended -- operation IF (running = 0) THEN -- If there's nothing running, IF (SR(2) = '1') THEN -- and there's a program suspended, SR(2) := '0'; -- Update the SR that there's -- no program suspended now. -- Change the ReadType to -- read the SR, and note that -- a program attempt is -- what's running. ReadType := ReadStatReg; running := WriteProgram; Completion := NOW + W16_ProgWordWOBuffer; SR(7) := '0'; -- And note the device is busy ELSIF (SR(6) = '1') THEN -- An erase was suspended. SR(6) := '0'; -- Clear the Erase Suspended flag SR(7) := '0'; -- Clear the Device Ready flag ReadType := ReadStatReg; -- Update the ReadType -- to read the Status Register running := WriteBlkErase; -- Note that a Block Erase is running IF BlockNum <= (2**(MaxAddrLine-15) -2) THEN Completion := NOW + W16_MainBlockErase; -- And note when the erase will -- complete. ELSE Completion := NOW + W16_ParmBlockErase; END IF; ELSE ASSERT (0>1) -- There's nothing to resume! -- The command's invalid. Complain. REPORT "Invalid Attempt To Resume" SEVERITY ERROR; END IF; ELSE ASSERT (0>1) -- The device is busy -- which makes the command invalid. REPORT "Invalid Attempt To Resume" SEVERITY ERROR; END IF; WHEN SuspendCmd => -- Command to suspend whatever is -- running. IF (running = WriteProgram) THEN -- a simple byte/word program -- is being suspended running := SuspensionLatency; -- Update running to note -- that we're waiting for a -- suspension to kick in. Completion := NOW + W16_ProgSuspToRead; -- Update the completion time -- to when we expect the -- suspension to suspend. SR(7) := '0'; -- Clear the device ready -- flag in the SR SR(2) := '1'; -- Set the Program Suspend -- flag in the SR ELSIF (running = WriteBlkErase) THEN -- A block erase is running running := SuspensionLatency; -- Update running to note -- that we're waiting for a -- suspension Completion := NOW + W16_EraseSuspToRead; -- Update the completion time -- to the new estimate SR(7) := '0'; -- Clear the Device Ready -- flag SR(6) := '1'; -- Set the Erase Suspended -- flag ELSIF (running = 0) THEN -- If nothing's running, ASSERT(0>1) -- the command isn't valid. REPORT "Invalid Command While Device Not Busy (Suspend)" SEVERITY ERROR; ELSE ASSERT(0>1) -- This may never happen. REPORT -- It means the device is "Invalid Attempt To Suspend" -- busy with something that SEVERITY ERROR; -- can't be suspended. END IF; -- Full Chip Erase, perhaps. WHEN OTHERS => -- This is an error condition ASSERT (0>1) -- corresponding to some REPORT "Unrecognized command written." -- command being sent which SEVERITY ERROR; -- isn't actually a command. ReadType := ReadArray; -- It's interpreted like $FF END CASE; WHEN WriteProgram => -- This subcase means that -- the device is expecting -- the second byte of the -- Program a Byte/Word cmd. ReadType := ReadStatReg; -- A read gives the SR now equal := '0'; IF (SR(6) = '1') THEN IF BlockNum = ErasingBlk THEN equal := '1'; END IF; END IF; -- Check versus block being erased -- If equal = 1, then the IF (equal = '1') THEN -- address is part of an SR := SR OR "00010000"; -- erase, and the prog fails END IF; -- Check versus lockbits IF ((wpb = '0') AND (((BlockNum <= 2**(MaxAddrLine-15)+6) AND (BlockNum >= 2**(MaxAddrLine-15)+5)) OR (BlockNum <= 2**(MaxAddrLine-15)-2))) THEN SR := SR OR "00010010"; -- If WP is asserted, and this END IF; -- block is lockable, -- then the prog fails -- Check versus powerdown IF (rpb = '0') THEN SR := SR OR "00010000"; -- If we have entered END IF; -- powerdown, the prog fails -- Check Vcc IF (VccSig = '0') THEN SR := SR OR "00010000"; -- If Vcc is out of range, END IF; -- the prog fails -- Check Vpp IF (vpp < Vpp5vLockout) THEN -- If Vpp is below the SR := SR OR "00011000"; -- lockout voltage, the END IF; -- prog fails IF (VppSig = '0') THEN SR := SR OR "00011000"; -- If Vpp is out of range, END IF; -- the prog fails IF NOT ((equal = '1') OR ((wpb = '0') AND (((BlockNum >= 2**(MaxAddrLine-15) + 5) AND (BlockNum <= 2**(MaxAddrLine-15) + 6)) OR (BlockNum <= 2**(MaxAddrLine-15) - 2))) OR (rpb = '0') OR (VccSig = '0') OR (VppSig = '0')) THEN -- If nothing's gone wrong, -- program the memory. IF (web = '1') THEN ASSERT (VppSig'LAST_EVENT >= tVPWH) REPORT "Violation of Vpp setup time (tVPWH)" SEVERITY ERROR; -- If it's a WE-controlled -- write, verify that Vpp was -- high early enough -- Vpp Setup time ELSIF (ceb = '1') THEN ASSERT (VppSig'LAST_EVENT >= tVPEH) REPORT "Violation of Vpp setup time (tVPEH)" SEVERITY ERROR; -- If it's a CE-controlled -- write, verify that Vcc was -- high early enough -- Vcc Setup time END IF; ProgrammingAddr := adder; equal := '1'; -- This loop serves to check -- if the memory can be -- programmed with the -- intended value, or if an -- erase would be needed FOR j IN 0 TO 15 LOOP IF ((hold_data(j) AND (NOT(memory(adder)(j)))) = '1') THEN equal := '0'; END IF; END LOOP; IF (equal = '0') -- Equal = 0 means that the -- value couldn't be -- programmed as desired -- without first erasing the -- cell. THEN SR := SR OR "00010000"; -- Set the prog fail flag ELSE memory(adder) := hold_data; -- Otherwise, write the value -- to the memory array. END IF; running := WriteProgram; -- Note that a program op -- is what's making the dev -- busy. SR(7) := '0'; -- Clear the Dev Ready flag -- Update the expected time -- that the busyness will end Completion := NOW + W16_ProgWordWOBuffer; END IF; -- The one starting with (equal ?= '1') WriteType := WriteCmd; -- And after all that, the -- next thing written is a -- command. WHEN WriteReadCfg => IF (datalo /= ReadCfgCmd2) THEN -- If it's the wrong cfrm, SR := SR OR "00110000"; -- set command invalid ReadType := ReadStatReg; END IF; -- Check versus powerdown IF (rpb = '0') THEN SR := SR OR "00010000"; -- If we have entered END IF; -- powerdown, fail -- Check Vcc IF (VccSig = '0') THEN SR := SR OR "00010000"; -- If Vcc is out of range, END IF; -- fail -- prog fail IF NOT (datalo /= ReadCfgCmd2 OR rpb = '0' OR vccsig = '0') THEN -- If all is well, update the RCR. FOR j IN 15 DOWNTO 0 LOOP RCR(j) := hold_add(j); END LOOP; END IF; ReadType := ReadArray; WriteType := WriteCmd; WHEN WriteBlkErase => -- Command to erase one blk ReadType := ReadStatReg; -- Next read shall be reading -- the status register. IF (datalo /= ConfirmCmd) THEN -- If the second byte wasn't SR := SR OR "00110000"; -- a CONFIRM, set the invalid END IF; -- command flags -- Check versus lockbits IF ((wpb = '0') AND (((BlockNum <= 2**(MaxAddrLine-15)+6) AND (BlockNum >= 2**(MaxAddrLine-15)+5)) OR (BlockNum <= 2**(MaxAddrLine-15)-2))) THEN SR := SR OR "00100010"; -- If WP is asserted, and this END IF; -- block is lockable, -- then the prog fails -- Check versus powerdown -- If RP's asserted, the IF (rpb = '0') THEN SR := SR OR "00100000"; -- device should be powering END IF; -- down, not erasing stuff. -- The erase fails. -- Set Erase Fail flag. -- Check Vcc -- If Vcc is out of range, IF (VccSig = '0') THEN SR := SR OR "00100000"; -- the erase certainly fails. END IF; -- Set Erase Fail flag. -- Check Vpp -- If Vpp is below lockout, IF (vpp < Vpp5vLockout) THEN -- the erase fails. SR := SR OR "00101000"; -- Set Erase Fail flag END IF; -- and Vpp Low flag IF (VppSig = '0') THEN SR := SR OR "00101000"; -- If Vpp is out of range, END IF; -- the erase fails. -- Set Erase Fail flag -- and Vpp Low flag IF NOT ((datalo /= ConfirmCmd) OR ((wpb = '0') AND (((BlockNum <= 2**(MaxAddrLine-15) + 6) AND (BlockNum >= 2**(MaxAddrLine-15) + 5)) OR (BlockNum >= 2**(MaxAddrLine-15) - 2))) OR -- If none of those things (rpb = '0') OR (VccSig = '0') OR -- happened, then erase the (VppSig = '0')) THEN -- block IF (web = '1') THEN -- If the write was -- WE-controlled, check that -- Vpp was high early enough. -- Vpp Setup time ASSERT (VppSig'LAST_EVENT >= tVPWH) REPORT "Violation of Vpp setup time (tVPWH)" SEVERITY ERROR; ELSIF (ceb = '1') THEN -- If the write was -- CE-controlled, check that -- Vpp was high early enough. -- Vpp Setup Time ASSERT (VppSig'LAST_EVENT >= tVPEH) REPORT "Violation of Vpp setup time (tVPEH)" SEVERITY ERROR; END IF; ErasingBlk := BlockNum; IF BlockNum <= 2**(MaxAddrLine - 15) - 2 THEN -- main block -- Here, we write all 1's to FOR j IN 0 TO 32767 LOOP -- the block, which erases it memory((BlockNum * 32768) + j) := "1111111111111111"; END LOOP; ELSE -- parm block FOR j IN 0 TO 4095 LOOP memory((2**MaxAddrLine - 32768) + (BlockNum - 2**(MaxAddrLine-15)+1) * 4096 + j) := "1111111111111111"; END LOOP; -- Don't laugh - it works. END IF; running := WriteBlkErase; -- Mark that a block erase is -- busying the device SR(7) := '0'; -- Clear the Dev Ready flag IF BlockNum <= (2**(MaxAddrLine-15) - 2) THEN Completion := NOW + W16_MainBlockErase; -- And note when the erase will -- complete. ELSE Completion := NOW + W16_ParmBlockErase; END IF; END IF; WriteType := WriteCmd; -- And the next write will be -- a command. WHEN OTHERS => -- This should never happen ASSERT (0>1) -- If we're here, the REPORT "Unrecognized WriteType achieved." -- WriteType state machine SEVERITY FAILURE; -- left all the valid states END CASE; -- Case of write types -- This is kinda sloppy -- After every write cycle, -- we check the memory -- location in the latch to -- see if we wrote Zs to it -- by mistake. If we did, FOR j IN 15 DOWNTO 0 LOOP -- turn the Zs into Xs. IF (memory(adder)(j) = 'Z') THEN memory(adder)(j) := 'X'; END IF; END LOOP; END IF; -- If WE rising edge encountered WHEN PowerDown => -- This state corresponds to RP asserted, and who cares about the rest of -- the lines? RP asserted means we're resetting and powered down. IF (running /= 0) AND (running /= ResetLatency) THEN -- If something's running, running := ResetLatency; -- it takes longer to reset. Completion := NOW + tPLRH; -- Note we're resetting, -- mark STS busy. ELSE -- If nothing's running SR := "10000000"; -- clear the status register dq <= "ZZZZZZZZZZZZZZZZ"; -- turn off the outputs ReadType := ReadArray; -- and get ready to read from RCR := "1000000000000000"; waitb <= 'H'; EdgeValid := 'Z'; paging := '0'; END IF; -- memory. IF (rpb = '1') THEN -- RP is no longer asserted next_state := Powerup; -- We're going to powerup ASSERT ((NOW - TimeRPL) >= TPLPH) OR (TimeRPL = 0 ns) -- Check that RP was asserted REPORT "Reset Pulse Width violation (TPLPH)" -- long enough SEVERITY ERROR; -- Reset Pulse width ASSERT (running = 0) -- Check that, if something -- was running, that RP was REPORT "Reset Pulse Width violation (TPLRH)" -- asserted long enough SEVERITY ERROR; -- Reset Pulse width running := 0; -- If we're leaving powerdown completion := 0 ns; -- by defn, nothing's running ELSE next_state := PowerDown; -- Nothing happened END IF; TimeWH := 0 ns; -- Clear the times which TimeWL := 0 ns; -- check WE and CE pulse TimeEH := 0 ns; -- widths TimeEL := 0 ns; WHEN OTHERS => -- If we got here, the main ASSERT (0>1) -- state machine crashed. REPORT "Unrecognized main state achieved" -- Won't happen. SEVERITY FAILURE; END CASE; -- END OF THE BIG STATE MACHINE -- ********************************************** -- Everything below here gets executed every pass. -- ********************************************** state := next_state; -- Update the big state machine clock1 <= NOT(clock1) AFTER 0.5 ns; -- Clock the other process -- Page buffer processing begins here IF (ceb = '1') OR (web = '0') OR (addrhi'EVENT) THEN paging := '0'; END IF; IF ((ceb = '1') OR (web = '0')) AND edgevalid /= 'Z' THEN edgevalid := 'Z'; END IF; ASSERT ((NOT(addr'EVENT)) OR (advb = '0') OR (advb'LAST_EVENT >= tVHAX)) REPORT "Violation of address hold on ADV rising edge (R18 - tVHAX)" SEVERITY ERROR; equal := '1'; -- Check if the address on the FOR j IN 0 to (MaxAddrLine-1) LOOP -- inputs equals the one in the IF hold_add(j) /= addr(j) THEN equal := '0'; -- latch END IF; END LOOP; IF timeEL >= timeWL THEN -- If the last write was -- CE-controlled, then IF (equal = '0') AND (timeEL /= 0 ns) AND (ceb = '1') AND (ceb'LAST_EVENT < tEHAX) THEN IF AddrHoldFlag = '0' THEN -- Check the Address Hold time ASSERT (0>1) -- Gripe where needed REPORT "Violation of address hold time on write (tEHAX)" SEVERITY ERROR; AddrHoldFlag := '1'; -- Set a flag if AddrHold was -- violated END IF; ELSE AddrHoldFlag := '0'; -- And clear the flag if it END IF; -- wasn't violated. -- The flag serves to suppress all but the first instance of a particular error. -- Without that logic, every nanosecond there would be an assertion, till the -- hold period was complete. ELSE -- If the last write was -- WE-controlled, then IF (equal = '0') AND (timeWL /= 0 ns) AND (web = '1') AND (web'LAST_EVENT < tWHAX) THEN IF AddrHoldFlag = '0' THEN -- Check the address hold time ASSERT (0>1) -- Gripe where needed REPORT "Violation of address hold time on write (tWHAX)" SEVERITY ERROR; AddrHoldFlag := '1'; -- Set a flag if it was violated END IF; ELSE AddrHoldFlag := '0'; -- and clear it if it wasn't. END IF; END IF; equal := '1'; -- Check if the data inputs have FOR j IN 0 to 15 LOOP -- changed since latching IF hold_data(j) /= dq(j) THEN equal := '0'; END IF; END LOOP; IF timeEL >= timeWL THEN -- If it's a CE-controlled write, -- The IF statement here breaks -- out to: -- 1) Data has changed since latch -- 2) Not immediately following -- powerup -- 3) CE is unasserted -- 4) CE has been unasserted less -- than the data hold time. IF (equal = '0') AND (timeEL /= 0 ns) AND (ceb = '1') AND (ceb'LAST_EVENT < tEHDX) THEN IF DataHoldFlag = '0' THEN -- Set a flag if Data Hold time ASSERT (0>1) -- was violated, and gripe. REPORT "Violation of data hold time on write (tEHDX)" SEVERITY ERROR; DataHoldFlag := '1'; END IF; ELSE DataHoldFlag := '0'; -- Clear if it wasn't END IF; ELSE -- On WE-controlled write, IF (equal = '0') AND (timeWL /= 0 ns) AND (web = '1') AND (web'LAST_EVENT < tWHDX) THEN IF DataHoldFlag = '0' THEN -- Gripe and set flag when Data Hold ASSERT (0>1) -- is violated REPORT "Violation of data hold time on write (tWHDX)" SEVERITY ERROR; DataHoldFlag := '1'; END IF; ELSE DataHoldFlag := '0'; -- and clear the flag when it's not END IF; END IF; IF NOT(((NOW - TimeSRValid) >= tQVVL) OR (VppSig = '1')) -- If Vpp is out of range, and THEN IF VppholdFlag = '0' THEN -- the device became free in the ASSERT (0>1) -- last tQVVL, there's a Vpp Hold REPORT "Violation of Vpp Hold time on write (tQVVL)" -- violation. SEVERITY ERROR; VppHoldFlag := '1'; END IF; ELSE VppHoldFlag := '0'; END IF; IF NOT (((NOW - TimeSRValid) >= tQVSL) OR (wpb = '1') OR -- If the device became free in ((wpb = '0') AND (wpb'LAST_EVENT >= (NOW - TimeSRValid)))) -- the last tQVSL, and WP went THEN IF WPHoldFlag = '0' THEN -- low since the device became free ASSERT (0>1) -- there's a WP High Hold time REPORT "Violation of WP# High Hold time on write (tQVSL)" -- violation. SEVERITY ERROR; WPHoldFlag := '1'; END IF; ELSE WPHoldFlag := '0'; END IF; IF NOT ((Running = 0) OR (VccSig = '1')) -- If Vcc is out of range, and the THEN IF VccMaintLFlag = '0' THEN -- device is busy, that's bad. ASSERT (0>1) REPORT "Vcc not maintained through latency period" SEVERITY ERROR; VccMaintLFlag := '1'; END IF; ELSE VccMaintLFlag := '0'; END IF; IF NOT (((SR(6) = '0') AND (SR(2) = '0')) OR (VccSig = '1')) -- If Vcc is out of range, and THEN IF VccMaintSFlag = '0' THEN -- something is suspended, ASSERT (0>1) -- that's also bad. REPORT "Vcc not maintained through suspended operation" SEVERITY ERROR; VccMaintSFlag := '1'; END IF; ELSE VccMaintSFlag := '0'; END IF; IF NOT ((Running = 0) OR (VppSig = '1')) -- If Vpp is out of range, and THEN IF VppMaintLFlag = '0' THEN -- something is running, that's bad ASSERT (0>1) REPORT "Vpp not maintained through latency period" SEVERITY ERROR; VppMaintLFlag := '1'; END IF; ELSE VppMaintLFlag := '0'; END IF; IF NOT (((SR(6) = '0') AND (SR(2) = '0')) OR (VppSig = '1')) -- If Vpp is out of range, and THEN IF VppMaintSFlag = '0' THEN -- something is suspended, that's ASSERT (0>1) -- bad, too. REPORT "Vpp not maintained through suspended operation" SEVERITY ERROR; VppMaintSFlag := '1'; END IF; ELSE VppMaintSFlag := '0'; END IF; -- This code runs when something gets finished (as determined by the time we wrote in the Completion -- variable when the something in question started. IF ((Completion /= 0 ns) AND (NOW >= Completion)) THEN -- a latency just finished TimeSRValid := NOW; -- Note when the SR became valid. -- A couple hold times need this, -- theoretically. SR(7) := '1'; -- Set the Dev Free flag Running := 0; -- Nothing is running, Completion := 0 ns; -- so there's no time at which it -- will complete. END IF; END PROCESS MAIN; EL_GUAPO:PROCESS -- This process exists solely to clock the main process. BEGIN WAIT ON clock1; clock2 <= not clock2 after 0.5 ns; END PROCESS EL_GUAPO; END behavior;