From b19c4c2883e8a2e1a97436d9b4afdcd10f2d19a4 Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Wed, 10 Jun 2015 20:00:51 +0000 Subject: [PATCH] - added model git-svn-id: http://moon:8086/svn/vhdl/trunk@1291 cc03376c-175c-47c8-b038-4cd826a8556b --- .../serial/S25fl032p/Model_Manual_English.pdf | Bin 0 -> 61136 bytes .../S25fl032p/Model_Manual_Japanese.pdf | Bin 0 -> 133648 bytes .../S25fl032p/model/model_release_history.txt | 227 ++ .../flash/serial/S25fl032p/model/s25fl032p.v | 2598 +++++++++++++++++ .../serial/S25fl032p/model/s25fl032p.vhd | 2532 ++++++++++++++++ .../serial/S25fl032p/model/s25fl032p_ver.ftm | 267 ++ .../serial/S25fl032p/model/s25fl032p_vhd.ftm | 279 ++ .../S25fl032p/utilities/CreateSDF/mk_sdf.cmd | 10 + .../utilities/CreateSDF/mk_sdf_204.pl | 462 +++ .../utilities/CreateSDF/my_mem_vhd.ftm | 205 ++ .../utilities/CreateSDF/testbench.sdf | 58 + .../utilities/CreateSDF/testbench.vhd | 1606 ++++++++++ .../S25fl032p/utilities/conversions.vhd | 1035 +++++++ .../serial/S25fl032p/utilities/gen_utils.vhd | 144 + 14 files changed, 9423 insertions(+) create mode 100644 lib/models/memory/flash/serial/S25fl032p/Model_Manual_English.pdf create mode 100644 lib/models/memory/flash/serial/S25fl032p/Model_Manual_Japanese.pdf create mode 100644 lib/models/memory/flash/serial/S25fl032p/model/model_release_history.txt create mode 100644 lib/models/memory/flash/serial/S25fl032p/model/s25fl032p.v create mode 100644 lib/models/memory/flash/serial/S25fl032p/model/s25fl032p.vhd create mode 100644 lib/models/memory/flash/serial/S25fl032p/model/s25fl032p_ver.ftm create mode 100644 lib/models/memory/flash/serial/S25fl032p/model/s25fl032p_vhd.ftm create mode 100644 lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/mk_sdf.cmd create mode 100644 lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/mk_sdf_204.pl create mode 100644 lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/my_mem_vhd.ftm create mode 100644 lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/testbench.sdf create mode 100644 lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/testbench.vhd create mode 100644 lib/models/memory/flash/serial/S25fl032p/utilities/conversions.vhd create mode 100644 lib/models/memory/flash/serial/S25fl032p/utilities/gen_utils.vhd diff --git a/lib/models/memory/flash/serial/S25fl032p/Model_Manual_English.pdf b/lib/models/memory/flash/serial/S25fl032p/Model_Manual_English.pdf new file mode 100644 index 0000000000000000000000000000000000000000..954c3f610ad959b640dca657e5e9ddcdae2a00eb GIT binary patch literal 61136 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 literal 0 HcmV?d00001 diff --git a/lib/models/memory/flash/serial/S25fl032p/Model_Manual_Japanese.pdf b/lib/models/memory/flash/serial/S25fl032p/Model_Manual_Japanese.pdf new file mode 100644 index 0000000000000000000000000000000000000000..de2f90936c33026d1bb917024b83c8ed0e180ec0 GIT binary patch literal 133648 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¨RM(hF`yxYLp*wzX^{ZARB}VL9f?hrZ~{9m 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 vital-amd-REL-s25fl032p-2008-01-22-1.tar.gz +# Release Date (DD/MM/YYYY) => 22/01/2008 +# Release Version => 1.0 +########################################## +RELEASE 1.1 + +# Release Label => vital-amd-REL-s25fl032p-2008-02-20-2.tar.gz +# Release Date (DD/MM/YYYY) => 20/02/2008 +# Release Version => 1.1 + +# Bugs fixed (from previous release) +- Quad functionality issue + +# Files modified (from previous release) +- s25fl032p.vhd +- s25fl032p.v +- testbench_s25fl032p_vhdl.vhd +- testbench_s25fl032p_verilog.vhd +- spansion_tc_pkg.vhd +- model_release_history.txt +########################################## +########################################## +Publication ID - SPANSION, S25FL064 032P DRS Rev.19, 2008 + +VITAL model author - Dragisa Stanojkovic + d-stanojkovic@hdl-dh.com +########################################## +########################################## +RELEASE 1.2 + +# Release Label => vital-amd-REL-s25fl032p-2008-03-05-1.tar.gz +# Release Date (DD/MM/YYYY) => 05/03/2008 +# Release Version => 1.2 + +# Bugs fixed (from previous release) +- MPM mode for Dual/Quad High Performance changed + +# Files modified (from previous release) +- s25fl032p.ftm +- s25fl032p.ftmv +- s25fl032p_vhdl.sdf +- s25fl032p_verilog.sdf +- s25fl032p.vhd +- s25fl032p.v +- testbench_s25fl032p_vhdl.vhd +- testbench_s25fl032p_verilog.vhd +- spansion_tc_pkg.vhd +- model_release_history.txt +########################################## +########################################## +RELEASE 1.3 + +# Release Label => vital-amd-REL-s25fl032p-2008-03-20-1.tar.gz +# Release Date (DD/MM/YYYY) => 20/03/2008 +# Release Version => 1.3 + +# Bugs fixed (from previous release) +- MPM mode removed + +# Files modified (from previous release) +- s25fl032p.vhd +- s25fl032p.v +- testbench_s25fl032p_vhdl.vhd +- testbench_s25fl032p_verilog.vhd +- spansion_tc_pkg.vhd +- model_release_history.txt +########################################## +########################################## + +VITAL model author - Jadranka Stoickov + j-stoickov@hdl-dh.com +########################################## +########################################## +RELEASE 1.4 + +# Release Label => vital-amd-REL-s25fl032p-2008-08-07-1.tar.gz +# Release Date (DD/MM/YYYY) => 07/08/2008 +# Release Version => 1.4 + +# Bugs fixed (from previous release) +- WEL bit fixed + +# Files modified (from previous release) +- s25fl032p.v +- model_release_history.txt +########################################## +########################################## +Publication ID - SPANSION, S25FL032P_00 Rev.01, 2008 + +VITAL model author - Jadranka Stoickov + j-stoickov@hdl-dh.com +########################################## +########################################## +RELEASE 1.5 + +# Release Label => vital-amd-REL-s25fl032p-2008-09-16-1.tar.gz +# Release Date (DD/MM/YYYY) => 16/09/2008 +# Release Version => 1.5 + +# Changes made (from previous release) +- alignment to new datasheet + +# Files modified (from previous release) +- s25fl032p.ftm +- s25fl032p.ftmv +- s25fl032p_vhdl.sdf +- s25fl032p_verilog.sdf +- s25fl032p.vhd +- s25fl032p.v +- testbench_s25fl032p_vhdl.vhd +- testbench_s25fl032p_verilog.vhd +- spansion_tc_pkg.vhd +- spansion_flash_testbench_struct.pdf +- spansion_flash_test_cases_list.pdf +- model_release_history.txt +########################################## +########################################## +Publication ID - SPANSION, S25FL129_064_032P_DRS Rev.23.2, Oct 13, 2008 + +VITAL model author - Jadranka Stoickov + j-stoickov@hdl-dh.com +########################################## +########################################## +RELEASE 1.6 + +# Release Label => vital-amd-REL-s25fl032p-2008-12-15-2.tar.gz +# Release Date (DD/MM/YYYY) => 15/12/2008 +# Release Version => 1.6 + +# Changes made (from previous release) +- alignment to new datasheet + +# Files modified (from previous release) +- s25fl032p.ftm +- s25fl032p.ftmv +- s25fl032p_vhdl.sdf +- s25fl032p_verilog.sdf +- s25fl032p.vhd +- s25fl032p.v +- testbench_s25fl032p_vhdl.vhd +- testbench_s25fl032p_verilog.vhd +- spansion_tc_pkg.vhd +- spansion_flash_testbench_struct.pdf +- spansion_flash_test_cases_list.pdf +- model_release_history.txt +########################################## +VITAL model author - Snezana Petrovic + s-petrovic@hdl-dh.com +########################################## +########################################## +RELEASE 1.7 + +# Release Label => vital-amd-REL-s25fl032p-2009-05-29-1.tar.gz +# Release Date (DD/MM/YYYY) => 29/05/2009 +# Release Version => 1.7 + +# Changes made (from previous release) +- Timing ranges in timing files corrected + +# Files modified (from previous release) +- s25fl032p.ftm +- s25fl032p.ftmv +- s25fl032p_vhdl.sdf +- s25fl032p_verilog.sdf +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +########################################## +RELEASE 1.8 + +# Release Label => vital-amd-REL-s25fl032p-2010-09-29-1.tar.gz +# Release Date (DD/MM/YYYY) => 29/09/2010 +# Release Version => 1.8 + +# Changes made (from previous release) +# 1. During the QUAD mode HOLD# input is not monitored for its normal function +# 2. Internal pull-up resistors for HOLD# and WP# inputs are implemented + +# Files modified (from previous release) +- s25fl032p.vhd +- s25fl032p.v +########################################## +########################################## +VITAL model author - Vesna Mancev + v-mancev@hdl-dh.com +########################################## +########################################## +RELEASE 1.9 + +# Release Label => vital-amd-REL-s25fl032p-2011-12-15-1.tar.gz +# Release Date (DD/MM/YYYY) => 15/12/2011 +# Release Version => 1.9 + +# Changes made (from previous release) +- alignment to new datasheet (S25FL032P_00_05, October 5, 2009) + +# Files modified (from previous release) +- s25fl032p.ftm +- s25fl032p.ftmv +- s25fl032p_vhdl.sdf +- s25fl032p_verilog.sdf +- s25fl032p.vhd +- s25fl032p.v +- testbench_s25fl032p_vhdl.vhd +- testbench_s25fl032p_verilog.vhd +- spansion_tc_pkg.vhd +- spansion_flash_testbench_struct.pdf +- spansion_flash_test_cases_list.pdf +- model_release_history.txt +########################################## \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl032p/model/s25fl032p.v b/lib/models/memory/flash/serial/S25fl032p/model/s25fl032p.v new file mode 100644 index 0000000..f7e8f01 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl032p/model/s25fl032p.v @@ -0,0 +1,2598 @@ +////////////////////////////////////////////////////////////////////////////// +// File name : s25fl032p.v +////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2011 Spansion, LLC. +// +// MODIFICATION HISTORY : +// +// version: | author: | mod date: | changes made: +// V1.0 D.Stanojkovic 08 Jan 22 Inital Release +// V1.1 D.Stanojkovic 08 Feb 20 BP bits setting corrected +// V1.2 D.Stanojkovic 08 Mar 05 MPM mode corrected +// V1.3 D.Stanojkovic 08 Mar 20 MPM mode removed +// V1.4 J.Stoickov 08 Aug 07 WEL bit corrected +// V1.5 J.Stoickov 08 Sep 16 Latest datasheet aligned +// V1.6 J.Stoickov 08 Dec 10 Latest datasheet aligned +// (S25FL129 064 032P) +// Program Error bit will not be +// set after programming in +// protect memory region +// V1.7 V.Mancev 10 Sep 29 Implementation of internal pull-up +// for HOLDNeg and WPNeg pins +// V1.8 V.Mancev 11 Dec 15 Latest datasheet aligned +// (S25FL032P_00_05) +////////////////////////////////////////////////////////////////////////////// +// PART DESCRIPTION: +// +// Library: FLASH +// Technology: FLASH MEMORY +// Part: S25FL032P +// +// Description: 32 Megabit Serial Flash Memory with 104 MHz SPI Bus Interface +// Comments : +// For correct simulation, simulator resolution should be set to 1 ps +// +////////////////////////////////////////////////////////////////////////////// +// Known Bugs: +// +////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// MODULE DECLARATION // +////////////////////////////////////////////////////////////////////////////// +`timescale 1 ps/1 ps + +module s25fl032p +( + SCK , + SI , + CSNeg , + HOLDNeg , + WPNeg , + SO +); +//////////////////////////////////////////////////////////////////////// +// Port / Part SOIn Declarations +//////////////////////////////////////////////////////////////////////// + input SCK ; + inout SI ; + + input CSNeg ; + inout HOLDNeg ; + inout WPNeg ; + inout SO ; + +// interconnect path delay signals + wire SCK_ipd ; + wire SI_ipd ; + + wire SI_in ; + assign SI_in = SI_ipd ; + + wire SI_out ; + assign SI_out = SI ; + + wire CSNeg_ipd ; + wire HOLDNeg_ipd ; + wire WPNeg_ipd ; + wire SO_ipd ; + + wire HOLDNeg_in ; + //Internal pull-up + assign HOLDNeg_in = (HOLDNeg_ipd === 1'bx) ? 1'b1 : HOLDNeg_ipd; + + wire HOLDNeg_out ; + assign HOLDNeg_out = HOLDNeg ; + + wire WPNeg_in ; + //Internal pull-up + assign WPNeg_in = (WPNeg_ipd === 1'bx) ? 1'b1 : WPNeg_ipd; + + wire WPNeg_out ; + assign WPNeg_out = WPNeg ; + + wire SOIn ; + assign SOIn = SO_ipd ; + + wire SOut ; + assign SOut = SO ; + +// internal delays + reg PP_in ; + reg PP_out ; + reg PU_in ; + reg PU_out ; + reg SE_in ; + reg SE_out ; + reg BE_in ; + reg BE_out ; + reg PE_in ; + reg PE_out ; + reg WR_in ; + reg WR_out ; + reg DP_in ; + reg DP_out ; + reg EP_in ; + reg EP_out ; + reg RES_in ; + reg RES_out ; + + reg SOut_zd = 1'bZ; + reg SOut_z = 1'bZ; + + wire SI_z ; + wire SO_z ; + + reg SIOut_zd = 1'bZ ; + reg SIOut_z = 1'bZ ; + + reg WPNegOut_zd = 1'bZ ; + reg HOLDNegOut_zd = 1'bZ ; + + assign SI_z = SIOut_z; + assign SO_z = SOut_z; + + parameter UserPreload = 1; + parameter mem_file_name = "none";//"s25fl032p.mem"; + parameter otp_file_name = "none";//"s25fl032p_secsi.mem"; + + parameter TimingModel = "DefaultTimingModel"; + + parameter PartID = "s25fl032p"; + parameter MaxData = 255; + parameter SecSize = 16'hFFFF; + parameter SecSize_4 = 4095; + parameter SecSize_8 = 8191; + parameter SecNum = 63; + parameter PageNum = 16'h3FFF; + parameter OTPSize = 511; + parameter OTPLoAddr = 9'h100; + parameter OTPHiAddr = 10'h2FF; + parameter HiAddrBit = 23; + parameter AddrRANGE = 24'h3FFFFF; + parameter BYTE = 8; + parameter Manuf_ID = 8'h01; + parameter ES = 8'h15; + parameter Jedec_ID = 8'h20; // first byte of Device ID + parameter DeviceID = 16'h0215; + parameter ExtendedBytes = 8'h4D; + parameter ReservedBytes = 8'h00; + + // If speed simulation is needed uncomment following line + +// `define SPEEDSIM; + + // powerup + reg PoweredUp; + + //FSM control signals + reg PDONE ; ////Prog. Done + reg PSTART ; ////Start Programming + + reg EDONE ; ////Era. Done + reg ESTART ; ////Start Erasing + + reg WDONE ; //// Writing Done + reg WSTART ; ////Start writing + + //Command Register + reg write; + reg cfg_write; + reg read_out; + + //Status reg. + reg[7:0] Status_reg = 8'b0; + reg[7:0] Status_reg_in = 8'b0; + reg[7:0] Sec_conf_reg = 8'b0; + reg[7:0] Sec_conf_reg_in = 8'b0; + + wire FREEZE; + wire QUAD; + wire TBPARM; + wire BPNV; + wire TBPROT; + assign FREEZE = Sec_conf_reg[0]; + assign QUAD = Sec_conf_reg[1]; + assign TBPARM = Sec_conf_reg[2]; + assign BPNV = Sec_conf_reg[3]; + assign TBPROT = Sec_conf_reg[5]; + + wire WIP; + wire WEL; + wire [2:0]BP; + wire E_ERR; + wire P_ERR; + wire SRWD; + assign WIP = Status_reg[0]; + assign WEL = Status_reg[1]; + assign BP = Status_reg[4:2]; + assign E_ERR = Status_reg[5]; + assign P_ERR = Status_reg[6]; + assign SRWD = Status_reg[7]; + + integer SA = 0; // 0 TO SecNum+1 + integer Byte_number = 0; + integer sect; + + //Address + integer Address = 0; // 0 - AddrRANGE + reg change_addr; + reg rd_fast; // = 1'b1; + reg rd_slow; + reg rd_jedec; + reg change_BP = 0; + reg rd_dual; + reg dual; + wire fast_rd; + wire rd; + wire rd_jid; + + wire RD_EQU_1; + assign RD_EQU_1 = rd_slow; + + wire RD_EQU_0; + assign RD_EQU_0 = ~rd_slow; + + reg hold_mode; + reg mpm_mode = 0; + wire hold; + + //Sector Protection Status + reg [SecNum:0] Sec_Prot = 64'b0; //= SecNum'b0; + + // timing check violation + reg Viol = 1'b0; + + integer Mem[0:AddrRANGE]; + integer OTPMem[OTPLoAddr: OTPHiAddr]; + + integer WByte[0:255]; + integer WOTPByte; + integer AddrLo; + integer AddrHi; + + reg[7:0] old_bit, new_bit; + integer old_int, new_int; + integer wr_cnt; + integer cnt; + + integer read_cnt = 0; + integer read_addr = 0; + reg[7:0] data_out; + reg[647:0] ident_out; + + reg oe = 1'b0; + event oe_event; + + integer CFI_array[8'h07:8'h50]; + reg [591:0] CFI_array_tmp; + reg [7:0] CFI_tmp; + + reg[15:0] PR_LOCK1; + reg[15:0] PR_LOCK2; + reg[15:0] PR_LOCK3; + +/////////////////////////////////////////////////////////////////////////////// +//Interconnect Path Delay Section +/////////////////////////////////////////////////////////////////////////////// + + buf (SCK_ipd, SCK); + buf (SI_ipd, SI); + + buf (CSNeg_ipd, CSNeg); + buf (HOLDNeg_ipd, HOLDNeg); + buf (WPNeg_ipd, WPNeg); + buf (SO_ipd, SO); + +/////////////////////////////////////////////////////////////////////////////// +// Propagation delay Section +/////////////////////////////////////////////////////////////////////////////// + nmos (SO, SO_z , 1); + + nmos (SI, SI_z , 1); + nmos (HOLDNeg, HOLDNegOut_zd , 1); + nmos (WPNeg, WPNegOut_zd , 1); + + wire deg_pin; + wire deg_sin; + wire deg_holdin; + //VHDL VITAL CheckEnable equivalents + wire dual_wr; + assign dual_wr = deg_holdin && QUAD; + wire dual_rd; + assign dual_rd = dual; + wire quad_wr; + assign quad_wr = SRWD && WEL ; + wire power; + assign power = PoweredUp; + + specify + // tipd delays: interconnect path delays , mapped to input port delays. + // In Verilog is not necessary to declare any tipd_ delay variables, + // they can be taken from SDF file + // With all the other delays real delays would be taken from SDF file + + // tpd delays + specparam tpd_SCK_SO =1; + specparam tpd_SCK_SI =1; + specparam tpd_CSNeg_SO =1; + specparam tpd_HOLDNeg_SO =1; + + specparam tsetup_SI_SCK =1; //tsuDAT / + specparam tsetup_CSNeg_SCK =1; // tCSS / + specparam tsetup_HOLDNeg_SCK =1; //tHD / + specparam tsetup_SCK_HOLDNeg =1; //tCH \ + specparam tsetup_WPNeg_CSNeg =1; //tWPS \ + + // thold values: hold times + specparam thold_SI_SCK =1; //thdDAT / + specparam thold_CSNeg_SCK =1; //tCSH / + specparam thold_HOLDNeg_SCK =1; //tCHHH / + specparam thold_SCK_HOLDNeg =1; //tHC \ + specparam thold_WPNeg_CSNeg =1; //tWPH \ + + // tpw values: pulse width + specparam tpw_SCK_fast_posedge =1; //tWH + specparam tpw_SCK_posedge =1; //tWH + specparam tpw_SCK_dual_posedge =1; //tWH + specparam tpw_SCK_rdid_posedge =1; //tWH + specparam tpw_SCK_fast_negedge =1; //tWL + specparam tpw_SCK_negedge =1; //tWL + specparam tpw_SCK_dual_negedge =1; //tWL + specparam tpw_SCK_rdid_negedge =1; //tWL + specparam tpw_CSNeg_read_posedge =1; //tCS + specparam tpw_CSNeg_pgm_posedge =1; //tCS + + // tperiod min (calculated as 1/max freq) + specparam tperiod_SCK_rd =1; // fSCK = 40MHz + specparam tperiod_SCK_fast_rd =1; // fSCK = 104MHz + specparam tperiod_SCK_dual_fast_rd =1; // fSCK = 80MHz + specparam tperiod_SCK_rdid =1; // fSCK = 50MHz + + // tdevice values: values for internal delays + `ifdef SPEEDSIM + // Page Program Operation + specparam tdevice_PP = 3e7; //30 us; + //Page Program Operation (ACC=9V)) + specparam tdevice_EP = 2.4e9; //2.4 ms; + //Sector Erase Operation + specparam tdevice_SE = 2e9; //2 ms; + //Bulk Erase Operation + specparam tdevice_BE = 64e9; //64 ms; + //Write Status Register Operation + specparam tdevice_WR = 5e8; // 0.5 ms; + //Software Protect Mode + specparam tdevice_DP = 10000000; // 10 us; + //Release from Software Protect Mode + specparam tdevice_RES = 30000000; // 30 us; + //Parameter block erase + specparam tdevice_PE = 800e6; //800 us; + //VCC (min) to CS# Low + specparam tdevice_PU = 300000000; //300 us; + `else + // Page Program Operation + specparam tdevice_PP = 3e9; //3 ms; + //Page Program Operation (ACC=9V)) + specparam tdevice_EP = 2.4e9; //2.4 ms; + //Sector Erase Operation + specparam tdevice_SE = 2e12; //2 s; + //Bulk Erase Operation + specparam tdevice_BE = 64e12; //64 sec; + //Write Status Register Operation + specparam tdevice_WR = 50e9; // 50 ms; + //Software Protect Mode + specparam tdevice_DP = 10000000; // 10 us; + //Release from Software Protect Mode + specparam tdevice_RES = 30000000; // 30 us; + //Parameter block erase + specparam tdevice_PE = 800e9; //800 ms; + //VCC (min) to CS# Low + specparam tdevice_PU = 300000000; //300 us; + `endif//SPEEDSIM + +/////////////////////////////////////////////////////////////////////////////// +// Input Port Delays don't require Verilog description +/////////////////////////////////////////////////////////////////////////////// +// Path delays // +/////////////////////////////////////////////////////////////////////////////// + if (~dual) (SCK => SO) = tpd_SCK_SO; + if (dual) (SCK => SO) = tpd_SCK_SI; + if (CSNeg)(CSNeg => SO) = tpd_CSNeg_SO; + if (~dual) (HOLDNeg => SO) = tpd_HOLDNeg_SO; + if (dual) (HOLDNeg => SO) = tpd_HOLDNeg_SO; + + if (dual)(SCK => SI) = tpd_SCK_SI; + if (dual && CSNeg)(CSNeg => SI) = tpd_CSNeg_SO; + if (dual)(HOLDNeg => SI) = tpd_HOLDNeg_SO; + + if (dual && QUAD)(SCK => HOLDNeg) = tpd_SCK_SI; + if (dual && CSNeg && QUAD)(CSNeg => HOLDNeg) = tpd_CSNeg_SO; + + if (dual && QUAD)(SCK => WPNeg) = tpd_SCK_SI; + if (dual && CSNeg && QUAD)(CSNeg => WPNeg) = tpd_CSNeg_SO; +//////////////////////////////////////////////////////////////////////////////// +// Timing Violation // +//////////////////////////////////////////////////////////////////////////////// + $setup ( SI , posedge SCK &&& deg_sin, + tsetup_SI_SCK, Viol); + $setup ( negedge HOLDNeg, posedge SCK &&& dual_wr, + tsetup_HOLDNeg_SCK, Viol); + $setup ( posedge SCK , posedge HOLDNeg &&& dual_wr, + tsetup_SCK_HOLDNeg, Viol); + $setup ( CSNeg , posedge SCK &&& power, + tsetup_CSNeg_SCK, Viol); + $setup ( WPNeg , negedge CSNeg &&& WPNeg, + tsetup_WPNeg_CSNeg, Viol); + + $hold ( posedge SCK , SI &&& deg_sin, + thold_SI_SCK, Viol); + $hold ( posedge HOLDNeg , posedge SCK &&& dual_wr, + thold_SCK_HOLDNeg, Viol); + $hold ( posedge SCK , CSNeg &&& power, + thold_CSNeg_SCK, Viol); + $hold ( posedge CSNeg , WPNeg &&& quad_wr, + thold_WPNeg_CSNeg, Viol); + $hold ( posedge SCK , negedge HOLDNeg &&& dual_wr, + thold_HOLDNeg_SCK, Viol); + + $width (posedge SCK &&& rd , tpw_SCK_posedge); + $width (posedge SCK &&& fast_rd , tpw_SCK_fast_posedge); + $width (posedge SCK &&& dual_rd , tpw_SCK_dual_posedge); + $width (posedge SCK &&& rd_jid , tpw_SCK_rdid_posedge); + $width (negedge SCK &&& rd , tpw_SCK_negedge); + $width (negedge SCK &&& fast_rd , tpw_SCK_fast_negedge); + $width (negedge SCK &&& dual_rd , tpw_SCK_dual_negedge); + $width (negedge SCK &&& rd_jid , tpw_SCK_rdid_negedge); + + $width (posedge CSNeg &&& RD_EQU_0, tpw_CSNeg_pgm_posedge); + $width (posedge CSNeg &&& RD_EQU_1, tpw_CSNeg_read_posedge); + + $period (posedge SCK &&& rd, tperiod_SCK_rd); + $period (posedge SCK &&& fast_rd, tperiod_SCK_fast_rd); + $period (posedge SCK &&& dual_rd, tperiod_SCK_dual_fast_rd); + $period (posedge SCK &&& rd_jid, tperiod_SCK_rdid); + + endspecify + +//////////////////////////////////////////////////////////////////////////////// +// Main Behavior Block // +//////////////////////////////////////////////////////////////////////////////// +// FSM states + parameter IDLE =4'd0; + parameter WRITE_SR =4'd1; + parameter DP_DOWN_WAIT =4'd2; + parameter DP_DOWN =4'd3; + parameter SECTOR_ER =4'd4; + parameter BULK_ER =4'd5; + parameter PAGE_PG =4'd6; + parameter OTP_PG =4'd7; + parameter P4_ER =4'd8; + parameter P8_ER =4'd9; + + reg [3:0] current_state; + reg [3:0] next_state; + +// Instructions + parameter NONE =5'd0; + parameter WREN =5'd1; + parameter WRDI =5'd2; + parameter WRR =5'd3; + parameter RDSR =5'd4; + parameter READ =5'd5; + parameter READ_ID =5'd6; + parameter RDID =5'd7; + parameter FAST_READ =5'd8; + parameter DUAL_READ =5'd9; + parameter QUAD_READ =5'd10; + parameter DH_READ =5'd11; + parameter QH_READ =5'd12; + parameter SE =5'd13; + parameter BE =5'd14; + parameter PP =5'd15; + parameter QPP =5'd16; + parameter DP =5'd17; + parameter RES_READ_ES =5'd18; + parameter CLSR =5'd19; + parameter RCR =5'd20; + parameter P4E =5'd21; + parameter P8E =5'd22; + parameter OTPP =5'd23; + parameter OTPR =5'd24; + reg [4:0] Instruct; + +//Bus cycle states + parameter STAND_BY =3'd0; + parameter CODE_BYTE =3'd1; + parameter ADDRESS_BYTES =3'd2; + parameter DUMMY_BYTES =3'd3; + parameter MODE_BYTE =3'd4; + parameter DATA_BYTES =3'd5; + + reg [2:0] bus_cycle_state; + + reg deq_pin; + always @(SOIn, SO_z) + begin + if (SOIn==SO_z) + deq_pin=1'b0; + else + deq_pin=1'b1; + end + // chech when data is generated from model to avoid setuphold check in + // those occasion + assign deg_pin=deq_pin; + + reg deq_sin; + always @(SI_in, SIOut_z) + begin + if (SI_in==SIOut_z) + deq_sin=1'b0; + else + deq_sin=1'b1; + end + // chech when data is generated from model to avoid setuphold check in + // those occasion + assign deg_sin=deq_sin; + + reg deq_holdin; + always @(HOLDNeg_ipd, HOLDNegOut_zd) + begin + if (HOLDNeg_ipd==HOLDNegOut_zd) + deq_holdin=1'b0; + else + deq_holdin=1'b1; + end + // check when data is generated from model to avoid setuphold check in + // those occasion + assign deg_holdin=deq_holdin; + + initial + begin : Init + + write = 1'b0; + cfg_write = 1'b0; + read_out = 1'b0; + Address = 0; + change_addr = 1'b0; + + PDONE = 1'b1; + PSTART = 1'b0; + + EDONE = 1'b1; + ESTART = 1'b0; + + WDONE = 1'b1; + WSTART = 1'b0; + + DP_in = 1'b0; + DP_out = 1'b0; + RES_in = 1'b0; + RES_out = 1'b0; + Instruct = NONE; + + bus_cycle_state = STAND_BY; + current_state = IDLE; + next_state = IDLE; + end + + //CFI + initial + begin: InitCFI + integer i; + integer j; + + CFI_array[8'h07] = 8'hFF; + CFI_array[8'h08] = 8'hFF; + CFI_array[8'h09] = 8'hFF; + CFI_array[8'h0A] = 8'hFF; + CFI_array[8'h0B] = 8'hFF; + CFI_array[8'h0C] = 8'hFF; + CFI_array[8'h0D] = 8'hFF; + CFI_array[8'h0E] = 8'hFF; + CFI_array[8'h0F] = 8'hFF; + CFI_array[8'h10] = 8'h51; + CFI_array[8'h11] = 8'h52; + CFI_array[8'h12] = 8'h59; + CFI_array[8'h13] = 8'h02; + CFI_array[8'h14] = 8'h00; + CFI_array[8'h15] = 8'h40; + CFI_array[8'h16] = 8'h00; + CFI_array[8'h17] = 8'h00; + CFI_array[8'h18] = 8'h00; + CFI_array[8'h19] = 8'h00; + CFI_array[8'h1A] = 8'h00; + //System interface string + CFI_array[8'h1B] = 8'h27; + CFI_array[8'h1C] = 8'h36; + CFI_array[8'h1D] = 8'h00; + CFI_array[8'h1E] = 8'h00; + CFI_array[8'h1F] = 8'h0B; + CFI_array[8'h20] = 8'h0B; + CFI_array[8'h21] = 8'h09; + CFI_array[8'h22] = 8'h0F; + CFI_array[8'h23] = 8'h01; + CFI_array[8'h24] = 8'h01; + CFI_array[8'h25] = 8'h02; + CFI_array[8'h26] = 8'h01; + //device geometry definition + CFI_array[8'h27] = 8'h16; + CFI_array[8'h28] = 8'h05; + CFI_array[8'h29] = 8'h05; + CFI_array[8'h2A] = 8'h08; + CFI_array[8'h2B] = 8'h00; + CFI_array[8'h2C] = 8'h02; + CFI_array[8'h2D] = 8'h1F; + CFI_array[8'h2E] = 8'h00; + CFI_array[8'h2F] = 8'h10; + CFI_array[8'h30] = 8'h00; + CFI_array[8'h31] = 8'h3D; + CFI_array[8'h32] = 8'h00; + CFI_array[8'h33] = 8'h00; + CFI_array[8'h34] = 8'h01; + CFI_array[8'h35] = 8'h00; + CFI_array[8'h36] = 8'h00; + CFI_array[8'h37] = 8'h00; + CFI_array[8'h38] = 8'h00; + CFI_array[8'h39] = 8'h00; + CFI_array[8'h3A] = 8'h00; + CFI_array[8'h3B] = 8'h00; + CFI_array[8'h3C] = 8'h00; + CFI_array[8'h3D] = 8'hFF; + CFI_array[8'h3E] = 8'hFF; + CFI_array[8'h3F] = 8'hFF; + //primary vendor-specific extended query + CFI_array[8'h40] = 8'h50; + CFI_array[8'h41] = 8'h52; + CFI_array[8'h42] = 8'h49; + CFI_array[8'h43] = 8'h31; + CFI_array[8'h44] = 8'h33; + CFI_array[8'h45] = 8'h15; + CFI_array[8'h46] = 8'h00; + CFI_array[8'h47] = 8'h01; + CFI_array[8'h48] = 8'h00; + CFI_array[8'h49] = 8'h05; + CFI_array[8'h4A] = 8'h00; + CFI_array[8'h4B] = 8'h01; + CFI_array[8'h4C] = 8'h03; + CFI_array[8'h4D] = 8'h85; + CFI_array[8'h4E] = 8'h95; + CFI_array[8'h4F] = 8'h07; + CFI_array[8'h50] = 8'h00; + + for(i=73;i>=0;i=i-1) + begin + CFI_tmp = CFI_array[8'h07-i+73]; + for(j=7;j>=0;j=j-1) + begin + CFI_array_tmp[8*i+j] = CFI_tmp[j]; + end + end + end + + // initialize memory + initial + begin: InitMemory + integer i; + + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = MaxData; + end + + if ((UserPreload) && !(mem_file_name == "none")) + begin + // Memory Preload + // s25fl032p.mem, memory preload file + // @aaaaaa - stands for address + // dd -
is byte to be written at Mem(aaaaaa++) + // (aaaaaa is incremented at every load) + $readmemh(mem_file_name,Mem); + end + + for (i=OTPLoAddr;i<=OTPHiAddr;i=i+1) + begin + OTPMem[i] = MaxData; + end + if (UserPreload && !(otp_file_name == "none")) + begin + //s25fl032p_secsi memory file + // / - comment + // @aaaaaa - stands for address within last defined + // sector + // dd -
is byte to be written at SecSi(aaaaaa++) + // (aa is incremented at every load) + // only first 1-5 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! + $readmemh(otp_file_name,OTPMem); + end + PR_LOCK1[15:8] = 16'h0; + PR_LOCK1[7:0] = OTPMem[256]; + + PR_LOCK2[15:8] = OTPMem[275]; + PR_LOCK2[7:0] = OTPMem[274]; + + PR_LOCK3[15:8] = OTPMem[533]; + PR_LOCK3[7:0] = OTPMem[532]; + end + + //Power Up time; + initial + begin + PoweredUp = 1'b0; + #tdevice_PU PoweredUp = 1'b1; + end + + always @(posedge DP_in) + begin:TDPr + #tdevice_DP DP_out = DP_in; + end + always @(negedge DP_in) + begin:TDPf + #1 DP_out = DP_in; + end + + always @(posedge RES_in) + begin:TRESr + #tdevice_RES RES_out = RES_in; + end + always @(negedge RES_in) + begin:TRESf + #1 RES_out = RES_in; + end + + always @(next_state or PoweredUp) + begin: StateTransition + if (PoweredUp) + begin + current_state = next_state; + end + end + + always @(negedge CSNeg_ipd) + begin:CheckCSOnPowerUP + if (~PoweredUp) + $display ("Device is selected during Power Up"); + end + +// /////////////////////////////////////////////////////////////////////////// +// // Instruction cycle decode +// /////////////////////////////////////////////////////////////////////////// + integer data_cnt = 0; + integer addr_cnt = 0; + integer code_cnt = 0; + integer mode_cnt = 0; + integer dummy_cnt = 0; + integer bit_cnt = 0; + + reg[2047:0] Data_in = 2048'b0; + integer quad_data_in [0:511]; + reg[3:0] quad_nybble = 4'b0; + reg[3:0] Quad_slv = 4'b0; + reg[7:0] code = 8'b0; + reg[7:0] code_in = 8'b0; + reg[7:0] Byte_slv = 8'b0; + reg[HiAddrBit:0] addr_bytes; + reg[23:0] Address_in = 8'b0; + reg[7:0] mode_bytes; + reg[7:0] mode_in; + + reg rising_edge_CSNeg_ipd = 1'b0; + reg falling_edge_CSNeg_ipd = 1'b0; + reg rising_edge_SCK_ipd = 1'b0; + reg falling_edge_SCK_ipd = 1'b0; + + always @(falling_edge_CSNeg_ipd or rising_edge_CSNeg_ipd + or rising_edge_SCK_ipd or falling_edge_SCK_ipd) + begin: Buscycle1 + integer i; + integer j; + integer k; + if (falling_edge_CSNeg_ipd) + begin + if (bus_cycle_state==STAND_BY) + begin + bus_cycle_state = CODE_BYTE; + Instruct = NONE; + write = 1'b1; + code_cnt = 0; + addr_cnt = 0; + data_cnt = 0; + mode_cnt = 0; + dummy_cnt = 0; + end + end + + if (rising_edge_SCK_ipd) + begin + if (~CSNeg_ipd) + begin + case (bus_cycle_state) + CODE_BYTE : + begin + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + code_in[code_cnt] = SI_in; + code_cnt = code_cnt + 1; + if (code_cnt == BYTE) + begin + for (i=0;i<=7;i=i+1) + begin + code[i] = code_in[7-i]; + end + case(code) + 8'b00000110 : + begin + Instruct = WREN; + bus_cycle_state = DATA_BYTES; + end + 8'b00000100 : + begin + Instruct = WRDI; + bus_cycle_state = DATA_BYTES; + end + 8'b00000001 : + begin + Instruct = WRR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000101 : + begin + Instruct = RDSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00000011 : + begin + Instruct = READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00001011 : + begin + Instruct = FAST_READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10011111 : + begin + Instruct = RDID; + bus_cycle_state = DATA_BYTES; + end + 8'b10010000 : + begin + Instruct = READ_ID; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10101011 : + begin + Instruct = RES_READ_ES; + bus_cycle_state = DUMMY_BYTES; + end + 8'b11011000 : + begin + Instruct = SE; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11000111 , 8'b01100000: + begin + Instruct = BE; + bus_cycle_state = DATA_BYTES; + end + 8'b00000010 : + begin + Instruct = PP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00110010 : + begin + Instruct = QPP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10111001 : + begin + Instruct = DP; + bus_cycle_state = DATA_BYTES; + end + 8'b00110000 : + begin + Instruct = CLSR; + bus_cycle_state = DATA_BYTES; + end + 8'b00110101 : + begin + Instruct = RCR; + bus_cycle_state = DATA_BYTES; + end + 8'b00100000 : + begin + Instruct = P4E; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01000000 : + begin + Instruct = P8E; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01000010 : + begin + Instruct = OTPP; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01001011 : + begin + Instruct = OTPR; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b00111011 : + begin + Instruct = DUAL_READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b01101011 : + begin + Instruct = QUAD_READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b10111011 : + begin + Instruct = DH_READ; + bus_cycle_state = ADDRESS_BYTES; + end + 8'b11101011 : + begin + Instruct = QH_READ; + bus_cycle_state = ADDRESS_BYTES; + end + endcase + end + end + end + + ADDRESS_BYTES : + begin + if (((Instruct == FAST_READ || Instruct == OTPR || + Instruct == DUAL_READ) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + ((Instruct == QUAD_READ) && QUAD)) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for (i=23;i>=23-HiAddrBit;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DUMMY_BYTES; + end + end + else if (Instruct == DH_READ && + ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + if (SOIn !== 1'b0 && SOIn !== 1'b1) + begin + mpm_mode = 0; + bus_cycle_state = STAND_BY; + end + else + begin + Address_in[2*addr_cnt] = SOIn; + Address_in[2*addr_cnt+1] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 12) + begin + addr_cnt = 0; + for (i=23;i>=23-HiAddrBit;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + end + else if (Instruct == QH_READ) + begin + if(QUAD) + begin + if (SOIn !== 1'b0 && SOIn !== 1'b1) + begin + mpm_mode = 0; + bus_cycle_state = STAND_BY; + end + else + begin + Address_in[4*addr_cnt] = HOLDNeg_in; + Address_in[4*addr_cnt+1] = WPNeg_in; + Address_in[4*addr_cnt+2] = SOIn; + Address_in[4*addr_cnt+3] = SI_in; + read_cnt = 0; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 6) + begin + addr_cnt = 0; + for (i=23;i>=23-HiAddrBit;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = MODE_BYTE; + end + end + end + else + begin + bus_cycle_state = STAND_BY; + end + end + else if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + Address_in[addr_cnt] = SI_in; + addr_cnt = addr_cnt + 1; + if (addr_cnt == 3*BYTE) + begin + for (i=23;i>=23-HiAddrBit;i=i-1) + begin + addr_bytes[23-i] = Address_in[i]; + end + Address = addr_bytes; + change_addr = 1'b1; + #1 change_addr = 1'b0; + bus_cycle_state = DATA_BYTES; + end + end + end + + MODE_BYTE : + begin + if((Instruct == DH_READ) && + ((HOLDNeg_in && ~QUAD) || QUAD)) + begin + mode_in[2*mode_cnt] = SOIn; + mode_in[2*mode_cnt+1] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/2) + begin + mode_cnt = 0; + for (i=7;i>=7-BYTE;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DATA_BYTES; + end + end + else if((Instruct == QH_READ) && QUAD) + begin + mode_in[4*mode_cnt] = HOLDNeg_in; + mode_in[4*mode_cnt+1] = WPNeg_in; + mode_in[4*mode_cnt+2] = SOIn; + mode_in[4*mode_cnt+3] = SI_in; + mode_cnt = mode_cnt + 1; + if (mode_cnt == BYTE/4) + begin + mode_cnt = 0; + for (i=7;i>=7-BYTE;i=i-1) + begin + mode_bytes[i] = mode_in[7-i]; + end + bus_cycle_state = DUMMY_BYTES; + end + end + dummy_cnt = 0; + end + + DUMMY_BYTES : + begin + if(QUAD && (Instruct == QUAD_READ || + Instruct == QH_READ)) + begin + dummy_cnt = dummy_cnt + 1; + if ((dummy_cnt == BYTE) && Instruct == QUAD_READ) + bus_cycle_state = DATA_BYTES; + else if ((dummy_cnt == BYTE/2) && + Instruct == QH_READ) + bus_cycle_state = DATA_BYTES; + end + else if((HOLDNeg_in && ~QUAD) || QUAD) + begin + dummy_cnt = dummy_cnt + 1; + if (dummy_cnt == BYTE && (Instruct == FAST_READ || + Instruct == OTPR || Instruct == DUAL_READ)) + bus_cycle_state = DATA_BYTES; + else if (dummy_cnt == 3*BYTE) + bus_cycle_state = DATA_BYTES; + end + end + + DATA_BYTES : + begin + if(QUAD && Instruct == QPP) + begin + quad_nybble = {HOLDNeg_in, WPNeg_in, SOIn, SI_in}; + if (data_cnt > 511) + begin + //In case of quad mode and QPP, + //if more than 512 bytes are sent to the device + for (i=0;i<=510;i=i+1) + begin + quad_data_in[i] = quad_data_in[i+1]; + end + quad_data_in[511] = quad_nybble; + data_cnt = data_cnt + 1; + end + else + begin + if( quad_nybble !== 4'bZZZZ) + begin + quad_data_in[data_cnt] = quad_nybble; + end + data_cnt = data_cnt + 1; + end + end + else if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt > 2047) + //In case of serial mode and PP, if more than 256 + //bytes are sent to the device + begin + if (bit_cnt == 0) + begin + for (i=0;i<=(255*BYTE-1);i=i+1) + begin + Data_in[i] = Data_in[i+8]; + end + end + Data_in[2040 + bit_cnt] = SI_in; + bit_cnt = bit_cnt + 1; + if (bit_cnt == 8) + begin + bit_cnt = 0; + end + data_cnt = data_cnt + 1; + end + else + begin + Data_in[data_cnt] = SI_in; + data_cnt = data_cnt + 1; + bit_cnt = 0; + end + end + end + endcase + end + end + if (falling_edge_SCK_ipd) + begin + if ((bus_cycle_state == DATA_BYTES) && (~CSNeg_ipd)) + begin + if (((Instruct == READ || Instruct == FAST_READ || + Instruct == DUAL_READ || Instruct == DH_READ || + Instruct == RES_READ_ES || Instruct == RDID || + Instruct == RDSR || Instruct == READ_ID || + Instruct == RCR || Instruct == OTPR) && + ((HOLDNeg_in && ~QUAD) || QUAD)) || + ((Instruct == QUAD_READ || Instruct == QH_READ) && QUAD)) + begin + read_out = 1'b1; + #1 read_out = 1'b0; + end + end + end + if (rising_edge_CSNeg_ipd) + begin + if ((bus_cycle_state != DATA_BYTES) && + (bus_cycle_state != DUMMY_BYTES)) + begin + bus_cycle_state = STAND_BY; + end + else + begin + if (bus_cycle_state == DATA_BYTES) + begin + if (mpm_mode && (mode_bytes[7:4] == 4'b1010) && + (Instruct == DH_READ || Instruct == QH_READ)) + begin + bus_cycle_state = ADDRESS_BYTES; + end + else + begin + mpm_mode = 0; + bus_cycle_state = STAND_BY; + end + if (Instruct == QPP) + begin + if (data_cnt > 0) + begin + if ((data_cnt % 2) == 0) + begin + write = 0; + for(i=0;i<=255;i=i+1) + begin + for(j=1;j>=0;j=j-1) + begin + Quad_slv = quad_data_in[(i*2)+(1-j)]; + for(k=3;k>=0;k=k-1) + begin + Byte_slv[4*j+k] = Quad_slv[k]; + end + end + WByte[i] = Byte_slv; + end + if (data_cnt > 512) + Byte_number = 255; + else + Byte_number = data_cnt/2 -1; + end + end + end + if ((HOLDNeg_in && ~QUAD) || QUAD) + begin + case (Instruct) + WRDI, + WREN, + DP, + BE, + SE, + P4E, + P8E, + CLSR: + begin + if (data_cnt == 0) + write = 1'b0; + end + + RES_READ_ES: + begin + write = 1'b0; + end + + WRR : + begin + if((HOLDNeg_in && ~QUAD) || QUAD) + begin + if (data_cnt == 8) + begin + write = 0; + cfg_write = 1'b0; + for(i=0;i<=7;i=i+1) + begin + Status_reg_in[i]= + Data_in[7-i]; + end + end + else if (data_cnt == 16) + begin + write = 0; + cfg_write = 1'b1; + for(i=0;i<=7;i=i+1) + begin + Status_reg_in[i]= + Data_in[7-i]; + Sec_conf_reg_in[i]= + Data_in[15-i]; + end + end + end + end + + PP : + begin + if (data_cnt > 0) + begin + if ((data_cnt % 8) == 0) + begin + write = 1'b0; + for (i=0;i<=255;i=i+1) + begin + for (j=7;j>=0;j=j-1) + begin + Byte_slv[j] = + Data_in[(i*8) + (7-j)]; + end + WByte[i] = Byte_slv; + end + if (data_cnt > 256*BYTE) + Byte_number = 255; + else + Byte_number = ((data_cnt/8) - 1); + end + end + end + + OTPP : + begin + if (data_cnt == 8) + begin + write = 1'b0; + for (j=7;j>=0;j=j-1) + begin + Byte_slv[j] = Data_in[7-j]; + end + WOTPByte = Byte_slv; + end + end + endcase + end + end + else + if (bus_cycle_state == DUMMY_BYTES) + begin + bus_cycle_state = STAND_BY; + if (((HOLDNeg_in && ~QUAD) || QUAD) && + (Instruct == RES_READ_ES) && (dummy_cnt == 0)) + write = 1'b0; + end + end + end + end + +// ///////////////////////////////////////////////////////////////////////// +// // Timing control for the Program Operations +// // start +// ///////////////////////////////////////////////////////////////////////// + + event pdone_event; + + always @(PSTART) + begin + if (PSTART && PDONE) + if (Sec_Prot[SA] == 1'b0) + begin + PDONE = 1'b0; + ->pdone_event; + end + end + + always @(pdone_event) + begin:pdone_process + PDONE = 1'b0; + #tdevice_PP PDONE = 1'b1; + end + +// ///////////////////////////////////////////////////////////////////////// +// // Timing control for the Write Status Register Operation +// // start +// ///////////////////////////////////////////////////////////////////////// + + event wdone_event; + + always @(WSTART) + begin + if (WSTART && WDONE) + begin + WDONE = 1'b0; + ->wdone_event; + end + end + + always @(wdone_event) + begin:wdone_process + WDONE = 1'b0; + #tdevice_WR WDONE = 1'b1; + end + +// ///////////////////////////////////////////////////////////////////////// +// // Timing control for the Erase Operations +// ///////////////////////////////////////////////////////////////////////// + time duration_erase; + + event edone_event; + + always @(ESTART) + begin: erase + if (ESTART && EDONE) + begin + if (Instruct == BE) + begin + duration_erase = tdevice_BE; + end + else if (Instruct == P4E || Instruct == P8E) + begin + duration_erase = tdevice_PE; + end + else + begin + duration_erase = tdevice_SE; + end + + EDONE = 1'b0; + ->edone_event; + end + end + + always @(edone_event) + begin : edone_process + EDONE = 1'b0; + #duration_erase EDONE = 1'b1; + end +// ///////////////////////////////////////////////////////////////////////// +// // Main Behavior Process +// // combinational process for next state generation +// ///////////////////////////////////////////////////////////////////////// + + reg rising_edge_PDONE = 1'b0; + reg rising_edge_EDONE = 1'b0; + reg rising_edge_WDONE = 1'b0; + reg rising_edge_DP_out = 1'b0; + reg falling_edge_write = 1'b0; + integer i; + integer j; + + always @(falling_edge_write or rising_edge_PDONE or rising_edge_WDONE + or rising_edge_EDONE or rising_edge_DP_out) + begin: StateGen1 + if (falling_edge_write) + begin + case (current_state) + IDLE : + begin + if (~write) + begin + if ((Instruct == WRR) && WEL) + begin + if (~(Status_reg[7] && ~WPNeg_in && ~QUAD)) + //HPM is disabled when the Quad I/O Mode is enabled + //(Quad bit = 1 in the Configuration Register) + next_state = WRITE_SR; + end + + else if ((Instruct == PP || Instruct == QPP) && + WEL) + begin + sect = Address / 24'h10000; + if (Sec_Prot[sect] == 1'b0) + next_state = PAGE_PG; + end + + else if (Instruct == OTPP && WEL) + begin + if(Address == 256 || Address == 257 || + ((Address >= 258 && Address <= 273) && + PR_LOCK1[(Address-258)/8] == 1'b1) + || Address == 274 + || Address == 275 || ((Address >= 276 && + Address <= 531) && PR_LOCK2[(Address-276)/16] + ==1'b1) || Address == 532 || Address == 533 || + ((Address >= 534 && Address <= 767) + && PR_LOCK3[(Address-534)/16] == 1'b1)) + next_state = OTP_PG; + end + + else if (Instruct == SE && WEL) + begin + sect = Address / 24'h10000; + if (Sec_Prot[sect] == 1'b0) + next_state = SECTOR_ER; + end + + else if (Instruct == P4E && WEL) + begin + sect = Address / 24'h10000; + if (Sec_Prot[sect] == 1'b0 && (((sect == 0 || + sect == 1) && ~TBPARM) || ((sect == SecNum || + sect == SecNum-1) && TBPARM))) + next_state = P4_ER; + end + + else if (Instruct == P8E && WEL) + begin + sect = Address / 24'h10000; + if (Sec_Prot[sect] == 1'b0 && (((sect == 0 || + sect == 1) && ~TBPARM) || ((sect == SecNum || + sect == SecNum-1) && TBPARM))) + next_state = P8_ER; + end + + else if (Instruct == BE && WEL) + begin + if (Status_reg[2]==1'b0 && Status_reg[3]==1'b0 && + Status_reg[4]==1'b0) + next_state = BULK_ER; + end + else if (Instruct == DP) + next_state = DP_DOWN_WAIT; + else + next_state = IDLE; + end + end + + DP_DOWN : + begin + if (~write) + begin + if (Instruct == RES_READ_ES) + next_state = IDLE; + end + end + + endcase + end + + if (rising_edge_PDONE) + begin + if (current_state==PAGE_PG || current_state==OTP_PG) + begin + next_state = IDLE; + end + end + + if (rising_edge_WDONE) + begin + if (current_state==WRITE_SR) + begin + next_state = IDLE; + end + end + + if (rising_edge_EDONE) + begin + if (current_state==SECTOR_ER || current_state==BULK_ER + || current_state==P4_ER || current_state==P8_ER) + begin + next_state = IDLE; + end + end + + if (rising_edge_DP_out) + begin + if (current_state==DP_DOWN_WAIT) + next_state = DP_DOWN; + end + + end + + /////////////////////////////////////////////////////////////////////////// + //FSM Output generation and general functionality + /////////////////////////////////////////////////////////////////////////// + reg rising_edge_read_out = 1'b0; + reg rising_edge_RES_out = 1'b0; + reg Instruct_event = 1'b0; + reg change_addr_event = 1'b0; + reg rising_edge_powered = 1'b0; + reg current_state_event = 1'b0; + + integer sector; + integer WData [0:255]; + integer WOTPData; + integer Addr; + integer Addr_tmp; + + always @(oe_event) + begin + oe = 1'b1; + #1 oe = 1'b0; + end + + always @(rising_edge_read_out or Instruct_event or + change_addr_event or oe or current_state_event or + falling_edge_write or EDONE or WDONE or PDONE or + CSNeg_ipd or rising_edge_RES_out or rising_edge_powered or + rising_edge_DP_out) + begin: Functionality + integer i,j; + + if (rising_edge_read_out) + begin + if (PoweredUp == 1'b1) + ->oe_event; + end + + if (Instruct_event) + begin + read_cnt = 0; + rd_fast = 1'b1; + rd_slow = 1'b0; + rd_jedec = 1'b0; + dual = 1'b0; + if (current_state == DP_DOWN_WAIT) + begin + if (DP_in == 1'b1) + begin + $display ("Command results can be corrupted"); + end + end + if (Instruct == DH_READ || Instruct == QH_READ) + begin + mpm_mode = 1; + end + end + + if (rising_edge_powered) + begin + //The Configuration Register FREEZE bit is cleared. + Sec_conf_reg[0] = 1'b0; + + if (BPNV == 1 && FREEZE == 0) + begin + //When BPNV is set to ‘1’,the BP2-0 bits in the Status Register + //are volatile and will be reset to binary 111 after power on reset. + Status_reg[4] = 1'b1;// BP2 + Status_reg[3] = 1'b1;// BP1 + Status_reg[2] = 1'b1;// BP0 + change_BP = 1'b1; + #1 change_BP = 1'b0; + end + end + + if (change_addr_event) + begin + read_addr = Address; + end + + if (oe || current_state_event) + begin + case (current_state) + IDLE : + begin + if (oe && ~RES_in) + begin + if (Instruct == RDSR) + begin + //Read Status Register + SOut_zd = Status_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + if (Instruct == RCR) + begin + //Read Security Conf. Register + SOut_zd = Sec_conf_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + else if (Instruct == READ || Instruct == FAST_READ) + begin + //Read Memory array + if (Instruct == READ) + begin + rd_fast = 1'b0; + rd_jedec = 1'b0; + rd_slow = 1'b1; + end + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else if (Instruct == DUAL_READ || Instruct == DH_READ) + begin + //Read Memory array + rd_fast = 1'b0; + rd_slow = 1'b0; + rd_jedec = 1'b0; + dual = 1'b1; + data_out[7:0] = Mem[read_addr]; + SOut_zd = data_out[7-2*read_cnt]; + SIOut_zd = data_out[6-2*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 4) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else if (Instruct == QUAD_READ || Instruct == QH_READ) + begin + //Read Memory array + rd_fast = 1'b0; + rd_slow = 1'b0; + rd_jedec = 1'b0; + dual = 1'b1; + data_out[7:0] = Mem[read_addr]; + HOLDNegOut_zd = data_out[7-4*read_cnt]; + WPNegOut_zd = data_out[6-4*read_cnt]; + SOut_zd = data_out[5-4*read_cnt]; + SIOut_zd = data_out[4-4*read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 2) + begin + read_cnt = 0; + if (read_addr == AddrRANGE) + read_addr = 0; + else + read_addr = read_addr + 1; + end + end + else if (Instruct == OTPR) + begin + if(read_addr>=OTPLoAddr && read_addr<=OTPHiAddr) + begin + //Read OTP Memory array + rd_fast = 1'b1; + rd_slow = 1'b0; + rd_jedec = 1'b0; + dual = 1'b0; + data_out = OTPMem[read_addr]; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else + begin + //OTP Read operation will not wrap to the + //starting address after the OTP address is at + //its maximum; + //instead, the data will be indeterminate. + SOut_zd = 1'bX; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + else if (Instruct == RDID) + begin + // Read ID + rd_fast = 1'b0; + rd_slow = 1'b0; + rd_jedec = 1'b1; + dual = 1'b0; + ident_out = {Manuf_ID,DeviceID,ExtendedBytes, + ReservedBytes,ReservedBytes, + ReservedBytes,CFI_array_tmp}; + SOut_zd = ident_out[647-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 648) + read_cnt = 0; + end + else if (Instruct == READ_ID) + begin + // --Read Manufacturer and Device ID + if (read_addr % 2 == 0) + begin + data_out[7:0] = Manuf_ID; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = read_addr + 1; + end + end + else if (read_addr % 2 == 1) + begin + data_out[7:0] = ES; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + begin + read_cnt = 0; + read_addr = 0; + end + end + end + end + else if (oe && RES_in) + begin + $display ("Command results can be corrupted"); + SOut_zd = 1'bX; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + + WRITE_SR, + SECTOR_ER, + BULK_ER, + P4_ER, + P8_ER, + OTP_PG, + PAGE_PG : + begin + if (oe && Instruct == RDSR) + begin + //Read Status Register + SOut_zd = Status_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + if (oe && Instruct == RCR) + begin + //Read Security Conf. Register + SOut_zd = Sec_conf_reg[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + DP_DOWN : + begin + if (oe && Instruct == RES_READ_ES) + begin + // Read ID + data_out[7:0] = ES; + SOut_zd = data_out[7-read_cnt]; + read_cnt = read_cnt + 1; + if (read_cnt == 8) + read_cnt = 0; + end + end + + endcase + end + + if (falling_edge_write) + begin + case (current_state) + IDLE : + begin + if (~write) + begin + if (RES_in == 1'b1 && Instruct != DP) + begin + $display ("Command results can be corrupted"); + end + if (Instruct == WREN) + Status_reg[1] = 1'b1; + else if (Instruct == WRDI) + Status_reg[1] = 1'b0; + else if (Instruct == WRR && WEL) + begin + if (~(Status_reg[7] && ~WPNeg_in && ~QUAD)) + begin + WSTART = 1'b1; + WSTART <= #1 1'b0; + Status_reg[0] = 1'b1; + end + else + begin + Status_reg[1] = 0; + end + end + else if ((Instruct == PP || Instruct == QPP) && + WEL) + begin + sect = Address / 24'h10000; + if (Sec_Prot[sect] == 1'b0) + begin + PSTART = 1'b1; + PSTART <= #1 1'b0; + Status_reg[0] = 1'b1; //WIP + Addr = Address; + Addr_tmp = Address; + SA = sect; + wr_cnt = Byte_number; + for (i=0;i<=wr_cnt;i=i+1) + begin + if (Viol != 1'b0) + WData[i] = -1; + else + WData[i] = WByte[i]; + end + end + else + begin + Status_reg[1] = 1'b0; + end + end + else if (Instruct == OTPP && WEL) + begin + if(Address == 256 || Address == 257 || + ((Address >= 258 && Address <= 273) && + PR_LOCK1[(Address-258)/8] == 1'b1) + || Address == 274 + || Address == 275 || ((Address >= 276 && + Address <= 531) && PR_LOCK2[(Address-276)/16] + ==1'b1) || Address == 532 || Address == 533 || + ((Address >= 534 && Address <= 767) + && PR_LOCK3[(Address-534)/16] == 1'b1)) + begin + PSTART = 1'b1; + PSTART <= #1 1'b0; + Status_reg[0] = 1'b1; //WIP + Addr = Address; + if (Viol != 1'b0 ) + WOTPData = -1; + else + WOTPData = WOTPByte; + end + else if (Address < 100 || Address > 767 ) + begin + Status_reg[6] = 1'b1; + Status_reg[1] = 1'b0; + end + else + begin + Status_reg[1] = 1'b0; + end + end + else if (Instruct == SE && WEL) + begin + sect = Address / 24'h10000; + if (Sec_Prot[sect] == 1'b0) + begin + ESTART = 1'b1; + ESTART <= #1 1'b0; + Status_reg[0] = 1'b1; + Addr = Address; + end + else + begin + Status_reg[1] = 1'b0; + end + end + else if (Instruct == BE && WEL) + begin + if(Status_reg[2]==1'b0 && Status_reg[3]==1'b0 && + Status_reg[4]==1'b0) + begin + ESTART = 1'b1; + ESTART <= #1 1'b0; + Status_reg[0] = 1'b1; + end + else + begin + Status_reg[1] = 1'b0; + end + end + else if (Instruct == P4E && WEL) + begin + sect = Address / 24'h10000; + if (((sect == 0 || + sect == 1) && ~TBPARM) || ((sect == SecNum || + sect == SecNum-1) && TBPARM)) + begin + if (Sec_Prot[sect] == 1'b0) + begin + ESTART = 1'b1; + ESTART <= #1 1'b0; + Status_reg[0] = 1'b1; + Addr = Address; + end + else + begin + Status_reg[1] = 1'b0; + end + end + else + begin + Status_reg[5] = 1'b1; + Status_reg[1] = 1'b0; + end + end + else if (Instruct == P8E && WEL) + begin + sect = Address / 24'h10000; + if (((sect == 0 || + sect == 1) && ~TBPARM) || ((sect == SecNum || + sect == SecNum-1) && TBPARM)) + begin + if (Sec_Prot[sect] == 1'b0) + begin + ESTART = 1'b1; + ESTART <= #1 1'b0; + Status_reg[0] = 1'b1; + Addr = Address; + end + else + begin + Status_reg[1] = 1'b0; + end + end + else + begin + Status_reg[5] = 1'b1; + Status_reg[1] = 1'b0; + end + end + else if (Instruct == CLSR) + begin + Status_reg[5] = 1'b0; + Status_reg[6] = 1'b0; + end + else if (Instruct == DP) + begin + RES_in <= 1'b0; + DP_in = 1'b1; + end + else if (Instruct == RES_READ_ES) + begin + RES_in <= 1'b1; + end + end + + end + + DP_DOWN : + begin + if (~write) + begin + if (Instruct == RES_READ_ES) + RES_in = 1'b1; + end + end + + endcase + end + + if(current_state_event || EDONE) + begin + case (current_state) + + SECTOR_ER : + begin + ADDRHILO_SEC(AddrLo, AddrHi, Addr); + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = -1; + end + if (EDONE) + begin + Status_reg[0] = 1'b0; + Status_reg[1] = 1'b0; + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = MaxData; + end + end + end + BULK_ER : + begin + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = -1; + end + + if (EDONE) + begin + Status_reg[0] = 1'b0; + Status_reg[1] = 1'b0; + for (i=0;i<=AddrRANGE;i=i+1) + begin + Mem[i] = MaxData; + end + end + end + P4_ER : + begin + ADDRHILO_PB4(AddrLo, AddrHi, Addr); + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = -1; + end + if (EDONE) + begin + Status_reg[0] = 1'b0; + Status_reg[1] = 1'b0; + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = MaxData; + end + end + end + P8_ER : + begin + ADDRHILO_PB8(AddrLo, AddrHi, Addr); + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = -1; + end + if (EDONE) + begin + Status_reg[0] = 1'b0; + Status_reg[1] = 1'b0; + for (i=AddrLo;i<=AddrHi;i=i+1) + begin + Mem[i] = MaxData; + end + end + end + endcase + end + + if(current_state_event || WDONE) + begin + if (current_state == WRITE_SR) + begin + if (WDONE) + begin + Status_reg[0] = 1'b0;//WIP + Status_reg[1] = 1'b0;//WEL + //SRWD bit + Status_reg[7] = Status_reg_in[7];//MSB first + + if (FREEZE == 0) + //The Freeze Bit, when set to 1, locks the current + //state of the BP2-0 bits in Status Register, + //the TBPROT and TBPARM bits in the Config Register + //As long as the FREEZE bit remains cleared to logic + //'0', the other bits of the Configuration register + //including FREEZE are writeable. + begin + Status_reg[4] = Status_reg_in[4];// BP2 + Status_reg[3] = Status_reg_in[3];// BP1 + Status_reg[2] = Status_reg_in[2];// BP0 + + if (cfg_write) + begin + Sec_conf_reg[0] = Sec_conf_reg_in[0];// FREEZE + + if (TBPARM == 1'b0) + begin + Sec_conf_reg[2] = Sec_conf_reg_in[2];//TBPARM + end + + if (TBPROT == 1'b0) + begin + Sec_conf_reg[5] = Sec_conf_reg_in[5];//TBPROT + end + + Sec_conf_reg[1] = Sec_conf_reg_in[1];// QUAD + + if (BPNV == 1'b0) + begin + Sec_conf_reg[3] = Sec_conf_reg_in[3];//BPNV + end + end + + change_BP = 1'b1; + #1 change_BP = 1'b0; + end + + end + end + end + + if(current_state_event || PDONE) + begin + if (current_state == PAGE_PG) + begin + ADDRHILO_PG(AddrLo, AddrHi, Addr); + cnt = 0; + + for (i=0;i<=wr_cnt;i=i+1) + begin + new_int = WData[i]; + old_int = Mem[Addr + i - cnt]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + if (~old_bit[j]) + new_bit[j]=1'b0; + new_int=new_bit; + end + + WData[i]= new_int; + end + else + begin + WData[i] = -1; + end + + Mem[Addr + i -cnt] = - 1; + + if ((Addr + i) == AddrHi) + begin + Addr = AddrLo; + cnt = i + 1; + end + end + + cnt = 0; + + if (PDONE) + begin + Status_reg[0] = 1'b0;//wip + Status_reg[1] = 1'b0; + for (i=0;i<=wr_cnt;i=i+1) + begin + Mem[Addr_tmp + i - cnt] = WData[i]; + if ((Addr_tmp + i) == AddrHi) + begin + Addr_tmp = AddrLo; + cnt = i + 1; + end + end + end + end + end + + if(current_state_event || PDONE) + begin + if (current_state == OTP_PG) + begin + new_int = WOTPData; + old_int = OTPMem[Addr]; + if (new_int > -1) + begin + new_bit = new_int; + if (old_int > -1) + begin + old_bit = old_int; + for(j=0;j<=7;j=j+1) + begin + if (~old_bit[j]) + new_bit[j] = 1'b0; + end + new_int = new_bit; + end + WOTPData = new_int; + end + else + begin + WOTPData = -1; + end + OTPMem[Addr] = -1; + if (PDONE) + begin + Status_reg[0] = 1'b0; + Status_reg[1] = 1'b0; + OTPMem[Addr] = WOTPData; + PR_LOCK1 = {OTPMem[257],OTPMem[256]}; + + PR_LOCK1[15:8] = OTPMem[257]; + PR_LOCK1[7:0] = OTPMem[256]; + PR_LOCK2[15:8] = OTPMem[275]; + PR_LOCK2[7:0] = OTPMem[274]; + PR_LOCK3[15:8] = OTPMem[533]; + PR_LOCK3[7:0] = OTPMem[532]; + end + end + end + + //Output Disable Control + if (CSNeg_ipd ) + begin + SIOut_zd = 1'bZ; + HOLDNegOut_zd = 1'bZ; + WPNegOut_zd = 1'bZ; + SOut_zd = 1'bZ; + end + + if (rising_edge_RES_out) + begin + if(RES_out) + begin + RES_in = 1'b0; + end + end + + if (rising_edge_DP_out) + begin + if (current_state == DP_DOWN_WAIT) + begin + DP_in = 1'b0; + end + end + + end + + always @(change_BP) + begin + if (change_BP) + begin + case (Status_reg[4:2]) + 3'b000 : + begin + Sec_Prot = 256'h0; + end + + 3'b001 : + begin + if (~Sec_conf_reg[5]) + begin + Sec_Prot[SecNum : (SecNum+1)*63/64] = 1'b1; + Sec_Prot[(SecNum+1)*63/64 - 1 : 0] = 126'h0; + end + else + begin + Sec_Prot[(SecNum+1)/64 - 1 : 0] = 2'b11; + Sec_Prot[SecNum : (SecNum+1)/64] = 126'h0; + end + end + + 3'b010 : + begin + if (~Sec_conf_reg[5]) + begin + Sec_Prot[SecNum : (SecNum+1)*31/32] = 4'hF; + Sec_Prot[(SecNum+1)*31/32 - 1 : 0] = 124'h0; + end + else + begin + Sec_Prot[(SecNum+1)/32 - 1 : 0] = 4'hF; + Sec_Prot[SecNum : (SecNum+1)/32] = 124'h0; + end + end + + 3'b011 : + begin + if (~Sec_conf_reg[5]) + begin + Sec_Prot[SecNum : (SecNum+1)*15/16] = 8'hFF; + Sec_Prot[(SecNum+1)*15/16 - 1 : 0] = 120'h0; + end + else + begin + Sec_Prot[(SecNum+1)/16 - 1 : 0] = 8'hFF; + Sec_Prot[SecNum : (SecNum+1)/16] = 120'h0; + end + end + + 3'b100 : + begin + if (~Sec_conf_reg[5]) + begin + Sec_Prot[SecNum : (SecNum+1)*7/8] = 16'hFFFF; + Sec_Prot[(SecNum+1)*7/8 - 1 : 0] = 112'h0; + end + else + begin + Sec_Prot[(SecNum+1)/8 - 1 : 0] = 16'hFFFF; + Sec_Prot[SecNum : (SecNum+1)/8] = 112'h0; + end + end + + 3'b101 : + begin + if (~Sec_conf_reg[5]) + begin + Sec_Prot[SecNum : (SecNum+1)*3/4] + = 32'hFFFFFFFF; + Sec_Prot[(SecNum+1)*3/4 - 1 : 0] = 96'h0; + end + else + begin + Sec_Prot[(SecNum+1)/4 - 1 : 0] + = 32'hFFFFFFFF; + Sec_Prot[SecNum : (SecNum+1)/4] = 96'h0; + end + end + + 3'b110 : + begin + if (~Sec_conf_reg[5]) + begin + Sec_Prot[SecNum : (SecNum+1)/2] + = 64'hFFFFFFFFFFFFFFFF; + Sec_Prot[(SecNum+1)/2 - 1 : 0] = 64'h0; + end + else + begin + Sec_Prot[(SecNum+1)/2 - 1 : 0] + = 64'hFFFFFFFFFFFFFFFF; + Sec_Prot[SecNum : (SecNum+1)/2] = 64'h0; + end + end + + 3'b111 : + begin + Sec_Prot = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + end + + endcase + end + end + + assign fast_rd = rd_fast; + assign rd = rd_slow; + assign rd_jid = rd_jedec; + + always @(SOut_zd or HOLDNeg_in or SIOut_zd) + begin + if (~HOLDNeg_in && ~QUAD) + begin + hold_mode = 1'b1; + SIOut_z = 1'bZ; + SOut_z = 1'bZ; + end + else + begin + if (hold_mode) + begin + SIOut_z <= #(tpd_HOLDNeg_SO) SIOut_zd; + SOut_z <= #(tpd_HOLDNeg_SO) SOut_zd; + hold_mode = 1'b0; + end + else + begin + SIOut_z = SIOut_zd; + SOut_z = SOut_zd; + hold_mode = 1'b0; + end + end + end + +// Procedure ADDRHILO_SEC + task ADDRHILO_SEC; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + sector = Addr / 20'h10000; + AddrLOW = sector * 20'h10000; + AddrHIGH = sector * 20'h10000 + 16'hFFFF; + end + endtask + +// Procedure ADDRHILO_PG + task ADDRHILO_PG; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer page; + begin + + page = Addr / 16'h100; + AddrLOW = page * 16'h100; + AddrHIGH = page * 16'h100 + 8'hFF; + + end + endtask + +// Procedure ADDRHILO_PB4 + task ADDRHILO_PB4; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + sector = Addr / 20'h10000; + if (sector == 0 || sector == 1 || + sector == SecNum || sector == SecNum-1) + begin + AddrLOW = (Address/(SecSize_4+1))*(SecSize_4+1); + AddrHIGH = (Address/(SecSize_4+1))*(SecSize_4+1) + SecSize_4; + end + end + endtask + +// Procedure ADDRHILO_PB8 + task ADDRHILO_PB8; + inout AddrLOW; + inout AddrHIGH; + input Addr; + integer AddrLOW; + integer AddrHIGH; + integer Addr; + integer sector; + begin + sector = Addr / 20'h10000; + if (sector == 0 || sector == SecNum-1) + begin + AddrLOW = (Address/(SecSize_8+1))*(SecSize_8+1); + AddrHIGH = (Address/(SecSize_8+1))*(SecSize_8+1) + SecSize_8; + end + if (sector == 1) + begin + AddrLOW = (Address/(SecSize_8+1))*(SecSize_8+1); + AddrHIGH = (Address/(SecSize_8+1))*(SecSize_8+1) + SecSize_8; + if (AddrHIGH > 20'h1FFFF) + AddrHIGH = 20'h1FFFF; + end + if (sector == SecNum) + begin + AddrLOW = (Address/(SecSize_8+1))*(SecSize_8+1); + AddrHIGH = (Address/(SecSize_8+1))*(SecSize_8+1) + SecSize_8; + if (AddrHIGH > 24'h3FFFFF) + AddrHIGH = 24'h3FFFFF; + end + end + endtask + + always @(negedge CSNeg_ipd) + begin + falling_edge_CSNeg_ipd = 1'b1; + #1 falling_edge_CSNeg_ipd = 1'b0; + end + + always @(posedge SCK_ipd) + begin + rising_edge_SCK_ipd = 1'b1; + #1 rising_edge_SCK_ipd = 1'b0; + end + + always @(negedge SCK_ipd) + begin + falling_edge_SCK_ipd = 1'b1; + #1 falling_edge_SCK_ipd = 1'b0; + end + + always @(posedge CSNeg_ipd) + begin + rising_edge_CSNeg_ipd = 1'b1; + #1 rising_edge_CSNeg_ipd = 1'b0; + end + + always @(negedge write) + begin + falling_edge_write = 1'b1; + #1 falling_edge_write = 1'b0; + end + + always @(posedge PDONE) + begin + rising_edge_PDONE = 1'b1; + #1 rising_edge_PDONE = 1'b0; + end + + always @(posedge WDONE) + begin + rising_edge_WDONE = 1'b1; + #1 rising_edge_WDONE = 1'b0; + end + + always @(posedge EDONE) + begin + rising_edge_EDONE = 1'b1; + #1 rising_edge_EDONE = 1'b0; + end + + always @(posedge DP_out) + begin + rising_edge_DP_out = 1'b1; + #1 rising_edge_DP_out = 1'b0; + end + + always @(posedge RES_out) + begin + rising_edge_RES_out = 1'b1; + #1 rising_edge_RES_out = 1'b0; + end + + always @(posedge read_out) + begin + rising_edge_read_out = 1'b1; + #1 rising_edge_read_out = 1'b0; + end + + always @(posedge PoweredUp) + begin + rising_edge_powered = 1'b1; + #1 rising_edge_powered = 1'b0; + end + + always @(Instruct) + begin + Instruct_event = 1'b1; + #1 Instruct_event = 1'b0; + end + + always @(change_addr) + begin + change_addr_event = 1'b1; + #1 change_addr_event = 1'b0; + end + + always @(current_state) + begin + current_state_event = 1'b1; + #1 current_state_event = 1'b0; + end + +endmodule \ No newline at end of file diff --git a/lib/models/memory/flash/serial/S25fl032p/model/s25fl032p.vhd b/lib/models/memory/flash/serial/S25fl032p/model/s25fl032p.vhd new file mode 100644 index 0000000..4eba2b4 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl032p/model/s25fl032p.vhd @@ -0,0 +1,2532 @@ +------------------------------------------------------------------------------- +-- 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 - stands for address + -- 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 - stands for address + -- 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; diff --git a/lib/models/memory/flash/serial/S25fl032p/model/s25fl032p_ver.ftm b/lib/models/memory/flash/serial/S25fl032p/model/s25fl032p_ver.ftm new file mode 100644 index 0000000..182ab94 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl032p/model/s25fl032p_ver.ftm @@ -0,0 +1,267 @@ + +FMF Timing for s25fl032p Parts + + +version: | author: | mod date: | changes made: + V1.0 D.Stanojkovic 08 Jan 22 Initial release + V1.1 D.Stanojkovic 08 Mar 05 New timmings added and changed + timming model labeling + V1.2 J.Stoickov 08 Sep 16 Latest datasheet update + V1.3 J.Stoickov 08 Dec 10 Changed timming model labeling + V1.4 S.Petrovic 09 May 29 Timing ranges corrected + V1.5 V.Mancev 11 Dec 13 Latest datasheet update + +1ns +s25fl032p + +S25FL032P0XMFI000_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI001_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI003_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI010_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI011_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI013_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI000_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI001_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI003_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI010_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI011_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI013_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV000_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV001_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV003_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV010_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV011_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV013_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV000_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV001_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV003_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV010_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV011_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV013_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI020_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI023_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI030_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI033_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV020_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV023_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV030_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV033_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +The values listed are for VCC=2.7V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + + (DELAY (ABSOLUTE + (COND ~dual (IOPATH SCK SO (5.4:6.7:8) (5.4:6.7:8) () (5.4:6.7:8) () (5.4:6.7:8))) + (COND dual (IOPATH SCK SO (6.5:8:9.5) (6.5:8:9.5) () (6.5:8:9.5) () (6.5:8:9.5))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~dual (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND dual (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + + (COND dual (IOPATH SCK SI (6.5:8:9.5) (6.5:8:9.5) () (6.5:8:9.5) () (6.5:8:9.5))) + (COND dual (IOPATH HOLDNeg SI () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND dual && CSNeg (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND dual && QUAD (IOPATH SCK HOLDNeg (6.5:8:9.5) (6.5:8:9.5) () (6.5:8:9.5) () (6.5:8:9.5))) + (COND dual && CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND dual && QUAD (IOPATH SCK WPNeg (6.5:8:9.5) (6.5:8:9.5) () (6.5:8:9.5) () (6.5:8:9.5))) + (COND dual && CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) +)) +(TIMINGCHECK + (SETUP CSNeg SCK (3)) + (SETUP HOLDNeg SCK (3)) + (SETUP SI SCK (3)) + (SETUP WPNeg CSNeg (20)) + + (HOLD CSNeg SCK (3)) + (HOLD HOLDNeg SCK (3)) + (HOLD SI SCK (2)) + (HOLD WPNeg CSNeg (100)) + + (WIDTH (COND fast_rd (negedge SCK)) (4.5)) + (WIDTH (COND fast_rd (posedge SCK)) (4.5)) + (WIDTH (COND dual_rd (negedge SCK)) (4.5)) + (WIDTH (COND dual_rd (posedge SCK)) (4.5)) + (WIDTH (COND rd (negedge SCK)) (4.5)) + (WIDTH (COND rd (posedge SCK)) (4.5)) + (WIDTH (COND rd_jid (negedge SCK)) (4.5)) + (WIDTH (COND rd_jid (posedge SCK)) (4.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (PERIOD (COND fast_rd SCK) (9.6)) + (PERIOD (COND rd SCK) (25.0)) + (PERIOD (COND rd_jid SCK) (20.0)) + (PERIOD (COND dual_rd SCK) (12.5)) +) + + + + +S25FL032P0XMFI000_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI001_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI003_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI010_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI011_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI013_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI000_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI001_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI003_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI010_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI011_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI013_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV000_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV001_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV003_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV010_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV011_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV013_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV000_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV001_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV003_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV010_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV011_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV013_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI020_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI023_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI030_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI033_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV020_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV023_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV030_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV033_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + + (DELAY (ABSOLUTE + (COND ~dual (IOPATH SCK SO (4.5:5.5:6.5) (4.5:5.5:6.5) () (4.5:5.5:6.5) () (4.5:5.5:6.5))) + (COND dual (IOPATH SCK SO (5.4:6.7:8) (5.4:6.7:8) () (5.4:6.7:8) () (5.4:6.7:8))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~dual (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND dual (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + + (COND dual (IOPATH SCK SI (5.4:6.7:8) (5.4:6.7:8) () (5.4:6.7:8) () (5.4:6.7:8))) + (COND dual (IOPATH HOLDNeg SI () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND dual && CSNeg (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND dual && QUAD (IOPATH SCK HOLDNeg (5.4:6.7:8) (5.4:6.7:8) () (5.4:6.7:8) () (5.4:6.7:8))) + (COND dual && CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND dual && QUAD (IOPATH SCK WPNeg (5.4:6.7:8) (5.4:6.7:8) () (5.4:6.7:8) () (5.4:6.7:8))) + (COND dual && CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) +)) +(TIMINGCHECK + (SETUP CSNeg SCK (3)) + (SETUP HOLDNeg SCK (3)) + (SETUP SI SCK (3)) + (SETUP WPNeg CSNeg (20)) + + (HOLD CSNeg SCK (3)) + (HOLD HOLDNeg SCK (3)) + (HOLD SI SCK (2)) + (HOLD WPNeg CSNeg (100)) + + (WIDTH (COND fast_rd (negedge SCK)) (4.5)) + (WIDTH (COND fast_rd (posedge SCK)) (4.5)) + (WIDTH (COND dual_rd (negedge SCK)) (4.5)) + (WIDTH (COND dual_rd (posedge SCK)) (4.5)) + (WIDTH (COND rd (negedge SCK)) (4.5)) + (WIDTH (COND rd (posedge SCK)) (4.5)) + (WIDTH (COND rd_jid (negedge SCK)) (4.5)) + (WIDTH (COND rd_jid (posedge SCK)) (4.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (PERIOD (COND fast_rd SCK) (9.6)) + (PERIOD (COND rd SCK) (25.0)) + (PERIOD (COND rd_jid SCK) (20.0)) + (PERIOD (COND dual_rd SCK) (12.5)) +) + + + + +S25FL032P0XMFI000_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI001_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI003_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI010_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI011_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI013_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI000_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI001_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI003_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI010_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI011_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI013_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV000_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV001_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV003_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV010_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV011_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV013_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV000_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV001_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV003_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV010_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV011_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV013_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI020_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI023_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI030_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI033_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV020_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV023_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV030_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV033_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=15pF, +Industrial Ta=-40 to +85 Celsius + + (DELAY (ABSOLUTE + (COND ~dual (IOPATH SCK SO (4.5:5.5:6.5) (4.5:5.5:6.5) () (4.5:5.5:6.5) () (4.5:5.5:6.5))) + (COND dual (IOPATH SCK SO (4.7:5.8:7) (4.7:5.8:7) () (4.7:5.8:7) () (4.7:5.8:7))) + + (COND CSNeg (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND ~dual (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND dual (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + + (COND dual (IOPATH SCK SI (4.7:5.8:7) (4.7:5.8:7) () (4.7:5.8:7) () (4.7:5.8:7))) + (COND dual (IOPATH HOLDNeg SI () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8))) + (COND dual && CSNeg (IOPATH CSNeg SI () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND dual && QUAD (IOPATH SCK HOLDNeg (4.7:5.8:7) (4.7:5.8:7) () (4.7:5.8:7) () (4.7:5.8:7))) + (COND dual && CSNeg && QUAD (IOPATH CSNeg HOLDNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) + + (COND dual && QUAD (IOPATH SCK WPNeg (4.7:5.8:7) (4.7:5.8:7) () (4.7:5.8:7) () (4.7:5.8:7))) + (COND dual && CSNeg && QUAD (IOPATH CSNeg WPNeg () () (5.4:6.7:8) () (5.4:6.7:8) ())) +)) +(TIMINGCHECK + (SETUP CSNeg SCK (3)) + (SETUP HOLDNeg SCK (3)) + (SETUP SI SCK (3)) + (SETUP WPNeg CSNeg (20)) + + (HOLD CSNeg SCK (3)) + (HOLD HOLDNeg SCK (3)) + (HOLD SI SCK (2)) + (HOLD WPNeg CSNeg (100)) + + (WIDTH (COND fast_rd (negedge SCK)) (4.5)) + (WIDTH (COND fast_rd (posedge SCK)) (4.5)) + (WIDTH (COND dual_rd (negedge SCK)) (4.5)) + (WIDTH (COND dual_rd (posedge SCK)) (4.5)) + (WIDTH (COND rd (negedge SCK)) (4.5)) + (WIDTH (COND rd (posedge SCK)) (4.5)) + (WIDTH (COND rd_jid (negedge SCK)) (4.5)) + (WIDTH (COND rd_jid (posedge SCK)) (4.5)) + (WIDTH (COND RD_EQU_1 (posedge CSNeg)) (10)) + (WIDTH (COND RD_EQU_0 (posedge CSNeg)) (50)) + (PERIOD (COND fast_rd SCK) (9.6)) + (PERIOD (COND rd SCK) (25.0)) + (PERIOD (COND rd_jid SCK) (20.0)) + (PERIOD (COND dual_rd SCK) (12.5)) +) + + + diff --git a/lib/models/memory/flash/serial/S25fl032p/model/s25fl032p_vhd.ftm b/lib/models/memory/flash/serial/S25fl032p/model/s25fl032p_vhd.ftm new file mode 100644 index 0000000..1e1dd63 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl032p/model/s25fl032p_vhd.ftm @@ -0,0 +1,279 @@ + +FMF Timing for s25fl032p Parts + + +version: | author: | mod date: | changes made: + V1.0 D.Stanojkovic 08 Jan 22 Initial release + V1.1 D.Stanojkovic 08 Mar 05 New timmings added and changed + timming model labeling + V1.2 J.Stoickov 08 Sep 16 Latest datasheet update + V1.3 J.Stoickov 08 Dec 10 Changed timming model labeling + V1.4 S.Petrovic 09 May 29 Timing ranges corrected + V1.5 V.Mancev 11 Dec 13 Latest datasheet update + +1ns +s25fl032p + +S25FL032P0XMFI000_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI001_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI003_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI010_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI011_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI013_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI000_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI001_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI003_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI010_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI011_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI013_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV000_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV001_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV003_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV010_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV011_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV013_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV000_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV001_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV003_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV010_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV011_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV013_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI020_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI023_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI030_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI033_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV020_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV023_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV030_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV033_F_30pF Spansion, S25FL032P_00_05, October 5, 2009 +The values listed are for full Vcc range VCC=2.7V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (IOPATH SCK SO (5.4:6.7:8) (5.4:6.7:8) () (5.4:6.7:8) () (5.4:6.7:8)) + (IOPATH SCK SI (6.5:8:9.5) (6.5:8:9.5) () (6.5:8:9.5) () (6.5:8:9.5)) + (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + )) + (TIMINGCHECK + (SETUP CSNeg SCK (3)) + (SETUP HOLDNeg SCK (3)) + (SETUP SI SCK (3)) + (SETUP WPNeg CSNeg (20)) + + (HOLD CSNeg SCK (3)) + (HOLD HOLDNeg SCK (3)) + (HOLD SI SCK (2)) + (HOLD WPNeg CSNeg (100)) + + (WIDTH (COND serial_fast (negedge SCK)) (4.5)) + (WIDTH (COND serial_fast (posedge SCK)) (4.5)) + (WIDTH (COND dual (negedge SCK)) (4.5)) + (WIDTH (COND dual (posedge SCK)) (4.5)) + (WIDTH (COND serial (negedge SCK)) (4.5)) + (WIDTH (COND serial (posedge SCK)) (4.5)) + (WIDTH (COND rd_jid (negedge SCK)) (4.5)) + (WIDTH (COND rd_jid (posedge SCK)) (4.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgm (posedge CSNeg)) (50)) + (PERIOD (COND serial_fast_rd SCK) (9.6)) + (PERIOD (COND serial_rd SCK) (25.0)) + (PERIOD (COND serial_rd_jid SCK) (20.0)) + (PERIOD (COND dual_fast_rd SCK) (12.5)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP) (DELAY (ABSOLUTE (DEVICE(1200000:1500000:3000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/EP) (DELAY (ABSOLUTE (DEVICE(1000000:1200000:2400000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE) (DELAY (ABSOLUTE (DEVICE(40e7:50e7:2e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(25e9:32e9:64e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WR) (DELAY (ABSOLUTE(DEVICE(50000000:50000000:50000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300000:300000:300000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/DP) (DELAY (ABSOLUTE (DEVICE(10000:10000:10000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PE) (DELAY (ABSOLUTE (DEVICE(20e7:20e7:80e7) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/RES) (DELAY (ABSOLUTE (DEVICE(30000:30000:30000) ) ) ) + + + +S25FL032P0XMFI000_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI001_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI003_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI010_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI011_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI013_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI000_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI001_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI003_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI010_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI011_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI013_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV000_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV001_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV003_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV010_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV011_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV013_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV000_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV001_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV003_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV010_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV011_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV013_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI020_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI023_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI030_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI033_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV020_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV023_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV030_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV033_R_30pF Spansion, S25FL032P_00_05, October 5, 2009 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=30pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (IOPATH SCK SO (4.5:5.5:6.5) (4.5:5.5:6.5) () (4.5:5.5:6.5) () (4.5:5.5:6.5)) + (IOPATH SCK SI (5.4:6.7:8) (5.4:6.7:8) () (5.4:6.7:8) () (5.4:6.7:8)) + (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + )) + (TIMINGCHECK + (SETUP CSNeg SCK (3)) + (SETUP HOLDNeg SCK (3)) + (SETUP SI SCK (3)) + (SETUP WPNeg CSNeg (20)) + + (HOLD CSNeg SCK (3)) + (HOLD HOLDNeg SCK (3)) + (HOLD SI SCK (2)) + (HOLD WPNeg CSNeg (100)) + + (WIDTH (COND serial_fast (negedge SCK)) (4.5)) + (WIDTH (COND serial_fast (posedge SCK)) (4.5)) + (WIDTH (COND dual (negedge SCK)) (4.5)) + (WIDTH (COND dual (posedge SCK)) (4.5)) + (WIDTH (COND serial (negedge SCK)) (4.5)) + (WIDTH (COND serial (posedge SCK)) (4.5)) + (WIDTH (COND rd_jid (negedge SCK)) (4.5)) + (WIDTH (COND rd_jid (posedge SCK)) (4.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgm (posedge CSNeg)) (50)) + (PERIOD (COND serial_fast_rd SCK) (9.6)) + (PERIOD (COND serial_rd SCK) (25.0)) + (PERIOD (COND serial_rd_jid SCK) (20.0)) + (PERIOD (COND dual_fast_rd SCK) (12.5)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP) (DELAY (ABSOLUTE (DEVICE(1200000:1500000:3000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/EP) (DELAY (ABSOLUTE (DEVICE(1000000:1200000:2400000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE) (DELAY (ABSOLUTE (DEVICE(40e7:50e7:2e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(25e9:32e9:64e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WR) (DELAY (ABSOLUTE(DEVICE(50000000:50000000:50000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300000:300000:300000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/DP) (DELAY (ABSOLUTE (DEVICE(10000:10000:10000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PE) (DELAY (ABSOLUTE (DEVICE(20e7:20e7:80e7) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/RES) (DELAY (ABSOLUTE (DEVICE(30000:30000:30000) ) ) ) + + + +S25FL032P0XMFI000_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI001_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI003_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI010_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI011_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFI013_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI000_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI001_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI003_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI010_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI011_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFI013_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV000_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV001_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV003_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV010_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV011_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XMFV013_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV000_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV001_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV003_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV010_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV011_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XNFV013_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI020_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI023_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI030_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHI033_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV020_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV023_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV030_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +S25FL032P0XBHV033_R_15pF Spansion, S25FL032P_00_05, October 5, 2009 +The values listed are for regulated Vcc range VCC=3.0V to 3.6V, CL=15pF, +Industrial Ta=-40 to +85 Celsius + +(DELAY (ABSOLUTE + (IOPATH SCK SO (4.5:5.5:6.5) (4.5:5.5:6.5) () (4.5:5.5:6.5) () (4.5:5.5:6.5)) + (IOPATH SCK SI (4.7:5.8:7) (4.7:5.8:7) () (4.7:5.8:7) () (4.7:5.8:7)) + (IOPATH HOLDNeg SO () () (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8) (5.4:6.7:8)) + (IOPATH CSNeg SO () () (5.4:6.7:8) () (5.4:6.7:8) ()) + )) + (TIMINGCHECK + (SETUP CSNeg SCK (3)) + (SETUP HOLDNeg SCK (3)) + (SETUP SI SCK (3)) + (SETUP WPNeg CSNeg (20)) + + (HOLD CSNeg SCK (3)) + (HOLD HOLDNeg SCK (3)) + (HOLD SI SCK (2)) + (HOLD WPNeg CSNeg (100)) + + (WIDTH (COND serial_fast (negedge SCK)) (4.5)) + (WIDTH (COND serial_fast (posedge SCK)) (4.5)) + (WIDTH (COND dual (negedge SCK)) (4.5)) + (WIDTH (COND dual (posedge SCK)) (4.5)) + (WIDTH (COND serial (negedge SCK)) (4.5)) + (WIDTH (COND serial (posedge SCK)) (4.5)) + (WIDTH (COND rd_jid (negedge SCK)) (4.5)) + (WIDTH (COND rd_jid (posedge SCK)) (4.5)) + (WIDTH (COND read (posedge CSNeg)) (10)) + (WIDTH (COND pgm (posedge CSNeg)) (50)) + (PERIOD (COND serial_fast_rd SCK) (9.6)) + (PERIOD (COND serial_rd SCK) (25.0)) + (PERIOD (COND serial_rd_jid SCK) (20.0)) + (PERIOD (COND dual_fast_rd SCK) (12.5)) +)) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PP) (DELAY (ABSOLUTE (DEVICE(1200000:1500000:3000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/EP) (DELAY (ABSOLUTE (DEVICE(1000000:1200000:2400000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/SE) (DELAY (ABSOLUTE (DEVICE(40e7:50e7:2e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/BE) (DELAY (ABSOLUTE (DEVICE(25e9:32e9:64e9) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/WR) (DELAY (ABSOLUTE(DEVICE(50000000:50000000:50000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PU) (DELAY (ABSOLUTE (DEVICE(300000:300000:300000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/DP) (DELAY (ABSOLUTE (DEVICE(10000:10000:10000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/PE) (DELAY (ABSOLUTE (DEVICE(20e7:20e7:80e7) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE %LABEL%/RES) (DELAY (ABSOLUTE (DEVICE(30000:30000:30000) ) ) ) + + diff --git a/lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/mk_sdf.cmd b/lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/mk_sdf.cmd new file mode 100644 index 0000000..f6d6cc7 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/mk_sdf.cmd @@ -0,0 +1,10 @@ +SET sdffile_suffix .sdf +SET use_global_timing_dir false +SET timingfile_dir /user/USERNAME/CreateSDF +SET timingfile_suffix .ftm +SET time_scale 1ns +SET local_path . +SET vendor MODELSIM_HOME +SET diagnostics on +SET vhdl_file testbench.vhd +SET lwb false diff --git a/lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/mk_sdf_204.pl b/lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/mk_sdf_204.pl new file mode 100644 index 0000000..5f2f2b8 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/mk_sdf_204.pl @@ -0,0 +1,462 @@ +#!/usr/local/bin/perl +# +# mk_sdf : Perl replacement for C mk_sdf +# +# Copyright (C) 2000, 1999 Free Model Foundry; http:/vhdl.org/fmf/ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# Author : R. Munden +# Date : 20001115 +# Version : 2.0.4 +# +# Revision history: +# 2.0: 19990702 +# o Intial release of perl version +# 2.0.1: 19990722 +# o fixed problem with . in path for TimingModels +# 2.0.2: 20000616 +# o changed instance search to work with Mentor +# 2.0.3: 20001115 +# o changed to parse ":" without leading space +# o fixed problem with . in path for TimingModels again +# 2.0.4: 20030405 +# o chaged SDF version to 3.0 +# +################################################################# +# +# command line arguments: + +# ARGV[0] - name of VHDL netlist + +# global variables: + +# %component_list - list of instance names by component name +# %instance_isin - list architectures by instances contained therein +# %instance_comp - list of component names by instance name +# %comp_lib - library each component (by name) is configured to +# @instance_list - array of all instance names in design in order found + +$version = "2.0.4"; +$design_name = ''; +$timing_dir = ''; +$diags = "off"; + +%keywords = (architecture => 1, + component => 1, + timingmodel => 1); + +# INPUT files +$CMD = "mk_sdf.cmd"; +$VHD = ''; # name of VHDL netlist + +# OUTPUT files +$RFV = "/tmp/short.vhd"; # reformatted VHDL +$sdf_file = ''; # name of SDF file + +&read_cmd_file; +&get_names; +&reformat; + +open INPUT, $RFV; +@lines = ; +close INPUT; + +$current_architecture = ""; + +foreach $line (@lines) +{ + @words = split / /, $line; + foreach $word (@words) + { + $keywords{$word} == "1" and do { &$word(@words);}; + if ($component_list{$word}) + { + $line =~ /(.+) : $word/ and do { + if ($1 !~ /for/) { # instantiation found + $component_list{$word} = $component_list{$word} . $1; + push (@instance_list, $1); + $instance_name = $1; + } + }; + $instance_comp{$1} = $word; + $instance_isin{$1} = $current_architecture; + if ( $diags ne off ) { + print "reading instance $instance_name: $word in $current_architecture\n"; + } + $line =~ /for all : $word use entity (.+)/ and do + { + @config = split(/\./, $1); + $comp_lib{$word} = $config[0];}; + } + } +} +if ( $diags ne off ) { + print "finished with netlist\n\n"; +} + +&begin_sdf; +&build_paths; +&close_sdf; +`rm $RFV`; + +print "$time\n"; + +sub architecture +{ + $current_architecture = $_[3]; + push (@architectures, $current_architecture); +} + +sub component +{ + if ($_[0] ne "end") + { + $name = $_[1]; + $arch_list{$current_architecture} = + $arch_list{$current_architecture} . " " . $name; + unless ($component_list{$name}) { $component_list{$name} = " ";} + } +} + +sub timingmodel +{ + $line =~ /timingmodel => \"(.+)\"/ and do { + $model = $1; + $model_name{$instance_name} = $model; + }; +} + +sub begin_sdf +{ + if ( $diags ne off ) { + print "writing SDF boilerplate\n"; + } + $time = localtime; + if (open(SDF, ">$sdf_file") !=1) { die "can't open $sdf_file\n";} + print "Opening $sdf_file\n"; + print SDF "(DELAYFILE\n"; + print SDF " (SDFVERSION \"3.0\")\n"; + print SDF " (DESIGN \"$design_name\")\n"; + print SDF " (DATE \"$time\")\n"; + print SDF " (VENDOR \"Free Model Foundry\")\n"; + print SDF " (PROGRAM \"SDF timing utility(tm)\")\n"; + print SDF " (VERSION \"$version\")\n"; + print SDF " (DIVIDER /)\n"; + print SDF " (VOLTAGE)\n"; + print SDF " (PROCESS)\n"; + print SDF " (TEMPERATURE)\n"; + print SDF " (TIMESCALE 1ns)\n"; +} + +sub build_paths +{ + foreach $instance_list (@instance_list) + { + @instance = $instance_list; + foreach $instance (@instance) + { + if ( $diags ne off ) { + print "working on $instance\n"; + } + if ($gtd =~ /true/i) { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; +# $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}./$timing_dir"; + } else { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; + } + $timing_file = "$path/$instance_comp{$instance}_vhd.ftm"; + $timing_file =~ s/\s//; + if ( $diags ne off ) { + print "$instance should be in $timing_file\n"; + } + if (-e $timing_file) { + if ($model_name{$instance} ne "") { + print SDF " (CELL\n"; + print SDF " (CELLTYPE \"$instance_comp{$instance}\")\n"; + $inst = $instance; + $full_inst = $instance; + while ($component_list{$instance_isin{$inst}}) { + $full_inst = "$component_list{$instance_isin{$inst}}/$full_inst"; + $full_inst =~ s/\s+//; + $inst = $component_list{$instance_isin{$inst}}; + $inst =~ s/\s+//; +# print SDF " (INSTANCE $component_list{$instance_isin{$instance}}/$instance)\n"; + } + print SDF " (INSTANCE $full_inst)\n"; + &add_timing; + } + } else { + if ( $diags ne off ) { + print "$timing_file not found!\n"; + } + } + } + } +} + +sub add_timing +{ + $timing_found = "false"; + $part_found = "false"; +# unless ($lib_path{$comp_lib{$instance_comp{$instance}}}) + unless ($timing_file) + { + print "path to $timing_file not found\n"; + exit; + } + if ($gtd =~ /true/i) { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; +# $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}./$timing_dir"; + } else { + $path = "$lib_path{$comp_lib{$instance_comp{$instance}}}/$timing_dir"; + } + $timing_file = "$path/$instance_comp{$instance}_vhd.ftm"; + if (open(TF, "<$timing_file") !=1) { warn "can't open $timing_file\n"; } + if ( $diags ne off ) { + print "reading $timing_file\n"; + } + $section_found = "false"; + while () + { + next unless (/$model_name{$instance}/i || ($part_found eq "true")); + $part_found = "true"; + if ( $diags ne off ) { + print "found entry for $model_name{$instance}\n"; + } + next unless (//i || ($timing_found eq "true")); + $timing_found = "true"; + next if (//i); + if (/<\/timing>/i) + { + print SDF " )\n"; + $timing_found = "false"; + $part_found = "false"; + $section_found = "true"; + last; + } else { + if (/%LABEL%/) + { + if ($component_list{$instance_isin{$instance}}) + { + $_ =~ s/%LABEL%/$component_list{$instance_isin{$instance}}\/$instance/; + } else { + $_ =~ s/%LABEL%/$instance/; + } + } + print SDF $_; + } + } + unless ($section_found eq "true") { + print "$model_name not found\n"; + } +} + +sub close_sdf +{ + print SDF ")\n"; + print "closing $sdf_file\n"; + close(SDF); +} + +# read mk_sdf.cmd + +sub read_cmd_file { + + if (open(CMD, $CMD) !=1) { die "can't open $CMD\n"; } + while () { + chop; + @fields = ''; + @fields = split; + unless ($fields[0] =~ /#/) { + if ($fields[0] =~ /SET/) { + if ($fields[1] =~ /vhdl_file/) {$VHD = $fields[2]} + if ($fields[1] =~ /sdffile_suffix/) {$suffix = $fields[2]} + if ($fields[1] =~ /use_global_timing_dir/) {$gtd = $fields[2]} + if ($fields[1] =~ /timingfile_dir/) {$timing_dir = $fields[2]} + if ($fields[1] =~ /vendor/) {$vendor = $fields[2]} + if ($fields[1] =~ /diagnostics/) {$diags = $fields[2]} + } + } + } + if ( $diags ne off ) { + print "\nmk_sdf diagnostics on\n\n"; + print "vhdl_file $VHD\n"; + print "sdffile_suffix $suffix\n"; + print "use_global_timing_dir $gtd\n"; + print "timingfile_dir $timing_dir\n"; + print "vendor $vendor\n\n"; + } +} +# + +# get name of netlist + +sub get_names +{ + + if ($ARGV[0] ne "") { $VHD = "$ARGV[0]"; } + + if ($ARGV[1] eq "") + { + @name = split(/\./,$VHD); + $design_name = $name[0]; + } else { + $design_name = "$ARGV[1]"; + } + $sdf_file = $design_name . $suffix; + if ($gtd =~ /false/i) + { + if ($vendor =~ /modeltech/i) { &read_mti; } + if ($vendor =~ /cadence/i) { &read_cds; } + } + if ( $diags ne off ) { + print "design name is $design_name\n\n"; + } +} +# +################################################################ +# + +# reformat netlist + +sub reformat +{ + $entfound = false; + + if (open(VHD, $VHD) !=1) { die "can't open $VHD\n"; } + if (open(OUT, ">$RFV") !=1) { die "can't open $OUT\n"; } + + while () { + if (/^--|library|package/i) { next } + if (/--/) { # strip embeded comments + @line = split("--"); + $_ = $line[0]; + } + s/:/ : /g; + s/;/ ;/g; + s/\s+/ /g; # reduces spaces and tabs + s/^\s//g; # no leading spaces + if (/entity/i) { + $entfound = "true"; + } + chomp; + if ( $entfound eq true ) { + print OUT lc($_); + if (/;|is|begin/i) { print OUT "\n"; } + } + } + + close OUT; + if ( $diags ne off ) { + print "reformatted netlist written to $RFV\n\n"; + } + +} + +# read ModelTech's modelsim.ini file + +sub read_mti +{ + $lib_found = "false"; + if ($ENV{MODELPATH}) + { + $ini_file = "$ENV{MODELPATH}/../modelsim.ini"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + if ($lib_found eq "true") + { + chomp; + if (/\[.+\]/) { last; } + s/\s+//; + @lib_line = split(/=/); + $lib_line[1] =~ s/\/work//; + $lib_path{$lib_line[0]} = $lib_line[1]; + } elsif (/\[Library\]/i) + { + $lib_found = "true"; + next; + } + } + } else { + print "\$MODELPATH environment variable not found\n"; + } + $lib_found = "false"; + if (-e "modelsim.ini") + { + $ini_file = "modelsim.ini"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + if ($lib_found eq "true") + { + chomp; + if (/\[.+\]/) { last; } + s/\s+//; + @lib_line = split(/=/); + $lib_line[1] =~ s/\/work//; + $lib_path{$lib_line[0]} = $lib_line[1]; + } elsif (/\[Library\]/i) + { + $lib_found = "true"; + next; + } + } + } else { + print "local modelsim.ini file not found, may not be needed\n"; + } +} + +# read Cadence's cds.lib file + +sub read_cds +{ + if ($ENV{CDS_VHDL}) + { + $ini_file = "$ENV{CDS_VHDL}/files/cds.lib"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + chomp; + s/\s+/ /; + if (/define/i) + { + @lib_line = split; + $lib_path{$lib_line[1]} = $lib_line[2]; + } + } + } else { + print "\$CDS_VHDL environment variable not found\n"; + } + if (-e "cds.lib") + { + $ini_file = "cds.lib"; + if (open(INI, "$ini_file") !=1) { die "can't open $ini_file\n";} + if ( $diags ne off ) { + print "reading $ini_file\n\n"; + } + while () + { + chomp; + s/\s+/ /; + if (/define/i) + { + @lib_line = split; + $lib_path{$lib_line[1]} = $lib_line[2]; + } + } + } else { + print "local cds.lib file not found, may not be needed\n"; + } +} diff --git a/lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/my_mem_vhd.ftm b/lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/my_mem_vhd.ftm new file mode 100644 index 0000000..2fc35c2 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/my_mem_vhd.ftm @@ -0,0 +1,205 @@ + +FMF Timing for testbench Parts + + +version: | author: | mod date: | changes made: + V1.0 VHD2FTM 03 July 11 Initial release + +1ns +am29lv640m + +MY_MEM +AM29LV640MH90R +AM29LV640ML90R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (90:90:90) (90:90:90)) + (IOPATH A0 DQ1 (25:25:25) (25:25:25)) + (IOPATH CENeg DQ0 (85:85:85) (85:85:85) (11:11:11) (85:85:85) (11:11:11) (85:85:85)) + (IOPATH OENeg DQ0 (20:20:20) (20:20:20) (11:11:11) (20:20:20) (11:11:11) (20:20:20)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (90)) + (IOPATH WENeg RY (0) (90)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (90:90:90)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH101 +AM29LV640ML101 +AM29LV640MH101R +AM29LV640ML101R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (100:100:100) (100:100:100)) + (IOPATH A0 DQ1 (30:30:30) (30:30:30)) + (IOPATH CENeg DQ0 (95:95:95) (95:95:95) (11:11:11) (95:95:95) (11:11:11) (95:95:95)) + (IOPATH OENeg DQ0 (25:25:25) (25:25:25) (11:11:11) (25:25:25) (11:11:11) (25:25:25)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (100)) + (IOPATH WENeg RY (0) (100)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (100:100:100)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH112 +AM29LV640ML112 +AM29LV640MH112R +AM29LV640ML112R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (110:110:110) (110:110:110)) + (IOPATH A0 DQ1 (40:40:40) (40:40:40)) + (IOPATH CENeg DQ0 (105:105:105) (105:105:105) (11:11:11) (105:105:105) (11:11:11) (105:105:105)) + (IOPATH OENeg DQ0 (35:35:35) (35:35:35) (11:11:11) (35:35:35) (11:11:11) (35:35:35)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (110)) + (IOPATH WENeg RY (0) (110)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (110:110:110)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + +AM29LV640MH120 +AM29LV640ML120 +AM29LV640MH120R +AM29LV640ML120R + + + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (120:120:120) (120:120:120)) + (IOPATH A0 DQ1 (40:40:40) (40:40:40)) + (IOPATH CENeg DQ0 (115:115:115) (115:115:115) (11:11:11) (115:115:115) (11:11:11) (115:115:115)) + (IOPATH OENeg DQ0 (35:35:35) (35:35:35) (11:11:11) (35:35:35) (11:11:11) (35:35:35)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (120)) + (IOPATH WENeg RY (0) (120)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (120:120:120)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + + diff --git a/lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/testbench.sdf b/lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/testbench.sdf new file mode 100644 index 0000000..02495dd --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/testbench.sdf @@ -0,0 +1,58 @@ +(DELAYFILE + (SDFVERSION "3.0") + (DESIGN "testbench") + (DATE "Wed Jan 28 15:15:41 2004") + (VENDOR "Free Model Foundry") + (PROGRAM "SDF timing utility(tm)") + (VERSION "2.0.4") + (DIVIDER /) + (VOLTAGE) + (PROCESS) + (TEMPERATURE) + (TIMESCALE 1ns) + (CELL + (CELLTYPE "my_mem") + (INSTANCE dut) + (DELAY (ABSOLUTE + (IOPATH A0 DQ0 (90:90:90) (90:90:90)) + (IOPATH A0 DQ1 (25:25:25) (25:25:25)) + (IOPATH CENeg DQ0 (85:85:85) (85:85:85) (11:11:11) (85:85:85) (11:11:11) (85:85:85)) + (IOPATH OENeg DQ0 (20:20:20) (20:20:20) (11:11:11) (20:20:20) (11:11:11) (20:20:20)) + (IOPATH RESETNeg DQ0 () () (0:0:0) () (0:0:0) ()) + (IOPATH CENeg RY (0) (90)) + (IOPATH WENeg RY (0) (90)) + )) + (TIMINGCHECK + (SETUP A0 CENeg (0:0:0)) + (SETUP A0 OENeg (15:15:15)) + (SETUP DQ0 CENeg (45:45:45)) + (HOLD CENeg RESETNeg (50:50:50)) + (HOLD OENeg WENeg (0:0:0)) + (HOLD A0 CENeg (45:45:45)) + (HOLD A0 OENeg (0:0:0)) + (HOLD DQ0 CENeg (0:0:0)) + (HOLD WENeg OENeg (0:0:0)) + (WIDTH (negedge RESETNeg) (500:500:500)) + (WIDTH (posedge OENeg) (20:20:20)) + (WIDTH (negedge WENeg) (35:35:35)) + (WIDTH (posedge WENeg) (30:30:30)) + (WIDTH (negedge CENeg) (45:45:45)) + (WIDTH (posedge CENeg) (30:30:30)) + (WIDTH (negedge A0) (90:90:90)) + )) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/WBPB) (DELAY (ABSOLUTE (DEVICE(11000:11000:11000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/POB) (DELAY (ABSOLUTE (DEVICE(100000:100000:100000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/SEO) (DELAY (ABSOLUTE (DEVICE(500000000:500000000:500000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/HANG) (DELAY (ABSOLUTE (DEVICE(400000000:400000000:400000000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/START_T1) (DELAY (ABSOLUTE (DEVICE(5000:5000:20000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/CTMOUT) (DELAY (ABSOLUTE (DEVICE(50000:50000:50000) ) ) ) ) + (CELL (CELLTYPE "VITALbuf") + (INSTANCE dut/READY) (DELAY (ABSOLUTE (DEVICE(20000:20000:20000) ) ) ) + ) +) diff --git a/lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/testbench.vhd b/lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/testbench.vhd new file mode 100644 index 0000000..c7d852a --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl032p/utilities/CreateSDF/testbench.vhd @@ -0,0 +1,1606 @@ +------------------------------------------------------------------------------ +-- File name : testbench_640.vhd +------------------------------------------------------------------------------- +-- Copyright (C) 2003 AMD. +-- +-- MODIFICATION HISTORY : +-- +-- version: | author: | mod date: | changes made: +-- V0.1 M.Marinkovic 11 July 03 Initial +-- v0.2 M.Marinkovic 28 Aug 03 Changed protected sector selection +-- +------------------------------------------------------------------------------- +-- PART DESCRIPTION: +-- +-- Description: +-- Generic test enviroment for verification of AMD flash memory +-- VITAL models.my_mem +-- +------------------------------------------------------------------------------- +-- Note: VHDL code formating not done +-- For High/Low sector protection selection change: +-- TimingModel constant and TimingModel generic value +-- +------------------------------------------------------------------------------- +LIBRARY IEEE; + USE IEEE.std_logic_1164.ALL; +--USE IEEE.VITAL_timing.ALL; +--USE IEEE.VITAL_primitives.ALL; + USE STD.textio.ALL; + +LIBRARY VITAL2000; + USE VITAL2000.vital_timing.ALL; + USE VITAL2000.vital_primitives.ALL; + +LIBRARY FMF; + USE FMF.gen_utils.ALL; + USE FMF.conversions.ALL; + + +LIBRARY work; + USE work.amd_tc_pkg.ALL; + +------------------------------------------------------------------------------- +-- ENTITY DECLARATION +------------------------------------------------------------------------------- +ENTITY testbench_640 IS +END testbench_640; + + +------------------------------------------------------------------------------- +-- ARCHITECTURE DECLARATION +------------------------------------------------------------------------------- +ARCHITECTURE vhdl_behavioral of testbench_640 IS + COMPONENT my_mem + GENERIC ( + -- tipd delays: interconnect path delays + tipd_A0 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A1 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A2 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A3 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A4 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A5 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A6 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A7 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A8 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A9 : VitalDelayType01 := VitalZeroDelay01; --address + tipd_A10 : VitalDelayType01 := VitalZeroDelay01; --lines + tipd_A11 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A12 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A13 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A14 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A15 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A16 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A17 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A18 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A19 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A20 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_A21 : VitalDelayType01 := VitalZeroDelay01; -- + + tipd_DQ0 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ1 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ2 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ3 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ4 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ5 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ6 : VitalDelayType01 := VitalZeroDelay01; -- data + tipd_DQ7 : VitalDelayType01 := VitalZeroDelay01; -- lines + tipd_DQ8 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ9 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ10 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ11 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ12 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ13 : VitalDelayType01 := VitalZeroDelay01; -- + tipd_DQ14 : VitalDelayType01 := VitalZeroDelay01; -- + + tipd_DQ15 : VitalDelayType01 := VitalZeroDelay01; -- DQ15/A-1 + + tipd_CENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_OENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WENeg : VitalDelayType01 := VitalZeroDelay01; + tipd_RESETNeg : VitalDelayType01 := VitalZeroDelay01; + tipd_WPNeg : VitalDelayType01 := VitalZeroDelay01; --WP#/ACC + tipd_BYTENeg : VitalDelayType01 := VitalZeroDelay01; + + -- tpd delays + tpd_A0_DQ0 : VitalDelayType01 := UnitDelay01;--tACC + tpd_A0_DQ1 : VitalDelayType01 := UnitDelay01;--tPACC + tpd_CENeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(tCE,tCE,tDF,-,tDF,-) + tpd_OENeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(tOE,tOE,tDF,-,tDF,-) + tpd_RESETNeg_DQ0 : VitalDelayType01Z := UnitDelay01Z; + --(-,-,0,-,0,-) + tpd_CENeg_RY : VitalDelayType01 := UnitDelay01; --tBUSY + tpd_WENeg_RY : VitalDelayType01 := UnitDelay01; --tBUSY + + --tsetup values + tsetup_A0_CENeg : VitalDelayType := UnitDelay; --tAS edge \ + tsetup_A0_OENeg : VitalDelayType := UnitDelay; --tASO edge \ + tsetup_DQ0_CENeg : VitalDelayType := UnitDelay; --tDS edge / + + --thold values + thold_CENeg_RESETNeg: VitalDelayType := UnitDelay; --tRH edge / + thold_OENeg_WENeg : VitalDelayType := UnitDelay; --tOEH edge / + thold_A0_CENeg : VitalDelayType := UnitDelay; --tAH edge \ + thold_A0_OENeg : VitalDelayType := UnitDelay; --tAHT edge \ + thold_DQ0_CENeg : VitalDelayType := UnitDelay; --tDH edge / + thold_WENeg_OENeg : VitalDelayType := UnitDelay; --tGHWL edge / + + --tpw values: pulse width + tpw_RESETNeg_negedge: VitalDelayType := UnitDelay; --tRP + tpw_OENeg_posedge : VitalDelayType := UnitDelay; --tOEPH + tpw_WENeg_negedge : VitalDelayType := UnitDelay; --tWP + tpw_WENeg_posedge : VitalDelayType := UnitDelay; --tWPH + tpw_CENeg_negedge : VitalDelayType := UnitDelay; --tCP + tpw_CENeg_posedge : VitalDelayType := UnitDelay; --tCEPH + tpw_A0_negedge : VitalDelayType := UnitDelay; --tWC tRC + + + -- tdevice values: values for internal delays + --Effective Write Buffer Program Operation tWHWH1 + tdevice_WBPB : VitalDelayType := 11 us; + --Program Operation + tdevice_POB : VitalDelayType := 100 us; + --Sector Erase Operation tWHWH2 + tdevice_SEO : VitalDelayType := 500 ms; + --Timing Limit Exceeded + tdevice_HANG : VitalDelayType := 400 ms; --? + --program/erase suspend timeout + tdevice_START_T1 : VitalDelayType := 5 us; + --sector erase command sequence timeout + tdevice_CTMOUT : VitalDelayType := 50 us; + --device ready after Hardware reset(during embeded algorithm) + tdevice_READY : VitalDelayType := 20 us; --tReady + + -- generic control parameters + InstancePath : STRING := DefaultInstancePath; + TimingChecksOn : BOOLEAN := DefaultTimingChecks; + MsgOn : BOOLEAN := DefaultMsgOn; + XOn : BOOLEAN := DefaultXon; + -- memory file to be loaded + mem_file_name : STRING ;--:= "am29lv640m.mem"; + prot_file_name : STRING ;--:= "am29lv640m_prot.mem"; + secsi_file_name : STRING ;--:= "am29lv_secsi.mem"; + + UserPreload : BOOLEAN ;--:= TRUE; + LongTimming : BOOLEAN ;--:= TRUE; + + -- For FMF SDF technology file usage + TimingModel : STRING --:= "AM29LV640MH90R" + ); + PORT ( + A21 : IN std_logic := 'U'; -- + A20 : IN std_logic := 'U'; -- + A19 : IN std_logic := 'U'; -- + A18 : IN std_logic := 'U'; -- + A17 : IN std_logic := 'U'; -- + A16 : IN std_logic := 'U'; -- + A15 : IN std_logic := 'U'; -- + A14 : IN std_logic := 'U'; -- + A13 : IN std_logic := 'U'; --address + A12 : IN std_logic := 'U'; --lines + A11 : IN std_logic := 'U'; -- + A10 : IN std_logic := 'U'; -- + A9 : IN std_logic := 'U'; -- + A8 : IN std_logic := 'U'; -- + A7 : IN std_logic := 'U'; -- + A6 : IN std_logic := 'U'; -- + A5 : IN std_logic := 'U'; -- + A4 : IN std_logic := 'U'; -- + A3 : IN std_logic := 'U'; -- + A2 : IN std_logic := 'U'; -- + A1 : IN std_logic := 'U'; -- + A0 : IN std_logic := 'U'; -- + + DQ15 : INOUT std_logic := 'U'; -- DQ15/A-1 + DQ14 : INOUT std_logic := 'U'; -- + DQ13 : INOUT std_logic := 'U'; -- + DQ12 : INOUT std_logic := 'U'; -- + DQ11 : INOUT std_logic := 'U'; -- + DQ10 : INOUT std_logic := 'U'; -- + DQ9 : INOUT std_logic := 'U'; -- data + DQ8 : INOUT std_logic := 'U'; -- lines + DQ7 : INOUT std_logic := 'U'; -- + DQ6 : INOUT std_logic := 'U'; -- + DQ5 : INOUT std_logic := 'U'; -- + DQ4 : INOUT std_logic := 'U'; -- + DQ3 : INOUT std_logic := 'U'; -- + DQ2 : INOUT std_logic := 'U'; -- + DQ1 : INOUT std_logic := 'U'; -- + DQ0 : INOUT std_logic := 'U'; -- + + CENeg : IN std_logic := 'U'; + OENeg : IN std_logic := 'U'; + WENeg : IN std_logic := 'U'; + RESETNeg : IN std_logic := 'U'; + WPNeg : IN std_logic := 'U'; --WP#/ACC + BYTENeg : IN std_logic := 'U'; + RY : OUT std_logic := 'U' --RY/BY# + ); + END COMPONENT; + + FOR ALL: my_mem USE ENTITY WORK.my_mem(VHDL_BEHAVIORAL); + + --------------------------------------------------------------------------- + --memory configuration + --------------------------------------------------------------------------- + CONSTANT MaxData : NATURAL := 16#FF#; --255; + CONSTANT SecSize : NATURAL := 16#FFFF#; --65535 + CONSTANT SecSiSize : NATURAL := 255; + CONSTANT SecNum : NATURAL := 127; + CONSTANT HiAddrBit : NATURAL := 21; + --Address of the Protected Sector +-- CONSTANT ProtSecNum : NATURAL := SecNum; + + --------------------------------------------------------------------------- + --model configuration + --------------------------------------------------------------------------- + CONSTANT mem_file : STRING := "am29lv640m.mem"; + CONSTANT prot_file : STRING := "am29lv640m_prot.mem"; + CONSTANT secsi_file : STRING := "am29lv_secsi.mem"; + + CONSTANT UserPreload : boolean := TRUE; + CONSTANT DebugInfo : boolean := FALSE; + CONSTANT LongTimming : boolean := TRUE; + CONSTANT TimingModel : STRING := "MY_MEM"; + -- "AM29LV640MH90R";--High sect prot. + -- "AM29LV128ML93R";--Low sect. prot. + --------------------------------------------------------------------------- + SIGNAL ProtSecNum : NATURAL := SecNum ; + + --Flash Memory Array + TYPE SecType IS ARRAY (0 TO SecSize) OF + INTEGER RANGE -1 TO MaxData; + TYPE MemArray IS ARRAY (0 TO SecNum) OF + SecType; + + --Common Flash Interface Query codes + TYPE CFItype IS ARRAY (16#10# TO 16#50#) OF + NATURAL RANGE 0 TO 16#FF#; + + --SecSi Sector + TYPE SecSiType IS ARRAY ( 0 TO SecSiSize) OF + INTEGER RANGE -1 TO MaxData; + + --------------------------------------------------------------------------- + -- memory declaration + --------------------------------------------------------------------------- + -- -- Mem(SecAddr)(Address).... + SHARED VARIABLE Mem : MemArray := (OTHERS => (OTHERS=> MaxData)); + SHARED VARIABLE CFI_array : CFItype :=(OTHERS=>0); + SHARED VARIABLE SecSi : SecSiType :=(OTHERS=>0); + + --command sequence + SHARED VARIABLE cmd_seq : cmd_seq_type; + + SIGNAL status : status_type := none; + SIGNAL sts_check : std_logic_vector(7 downto 0); + + + SIGNAL check_err : std_logic := '0'; + SIGNAL ErrorInTest : std_logic := '0'; -- + ---------------------------------------------------------------------------- + --Personality module: + -- + -- instanciates the DUT module and adapts generic test signals to it + -- TBD: block port + ---------------------------------------------------------------------------- + --DUT port + SIGNAL T_DQ : std_logic_vector(15 downto 0) := (OTHERS=>'U'); + SIGNAL T_A : std_logic_vector(HiAddrBit downto 0) := (OTHERS=>'U'); + SIGNAL T_RESETNeg : std_logic := 'U'; + SIGNAL T_CENeg : std_logic := 'U'; + SIGNAL T_WENeg : std_logic := 'U'; + SIGNAL T_OENeg : std_logic := 'U'; + SIGNAL T_WPNeg : std_logic := 'U'; + SIGNAL T_BYTENeg : std_logic := 'U'; + SIGNAL T_RY : std_logic := 'U'; + + --------------------------------------------------------------------------- + -- + --------------------------------------------------------------------------- + --SecSi ProtectionStatus + SHARED VARIABLE FactoryProt : std_logic := '1'; + --Sector Protection Status + SHARED VARIABLE Sec_Prot : std_logic_vector (SecNum downto 0) := + (OTHERS => '0'); + SHARED VARIABLE Sect : NATURAL RANGE 0 TO SecNum := 0; + SHARED VARIABLE Addr : NATURAL RANGE 0 TO SecSize := 0; + SHARED VARIABLE WriteData : NATURAL RANGE 0 TO MaxData := 0; + + + --CONSTANT + --timming parameters + CONSTANT RESETNeg_pw : time := 500 ns; --tRP + + SIGNAL pwron : std_logic := '0'; + + SIGNAL Tseries : NATURAL; + SIGNAL Tcase : NATURAL; + + SHARED VARIABLE ts_cnt : NATURAL RANGE 1 TO 30:=1; -- testseries counter + SHARED VARIABLE tc_cnt : NATURAL RANGE 0 TO 10:=0; -- testcase counter + + + BEGIN + DUT : my_mem + GENERIC MAP ( + -- tipd delays: interconnect path delays + tipd_A0 => VitalZeroDelay01, -- + tipd_A1 => VitalZeroDelay01, -- + tipd_A2 => VitalZeroDelay01, -- + tipd_A3 => VitalZeroDelay01, -- + tipd_A4 => VitalZeroDelay01, -- + tipd_A5 => VitalZeroDelay01, -- + tipd_A6 => VitalZeroDelay01, -- + tipd_A7 => VitalZeroDelay01, -- + tipd_A8 => VitalZeroDelay01, -- + tipd_A9 => VitalZeroDelay01, --address + tipd_A10 => VitalZeroDelay01, --lines + tipd_A11 => VitalZeroDelay01, -- + tipd_A12 => VitalZeroDelay01, -- + tipd_A13 => VitalZeroDelay01, -- + tipd_A14 => VitalZeroDelay01, -- + tipd_A15 => VitalZeroDelay01, -- + tipd_A16 => VitalZeroDelay01, -- + tipd_A17 => VitalZeroDelay01, -- + tipd_A18 => VitalZeroDelay01, -- + tipd_A19 => VitalZeroDelay01, -- + tipd_A20 => VitalZeroDelay01, -- + tipd_A21 => VitalZeroDelay01, -- + + tipd_DQ0 => VitalZeroDelay01, -- + tipd_DQ1 => VitalZeroDelay01, -- + tipd_DQ2 => VitalZeroDelay01, -- + tipd_DQ3 => VitalZeroDelay01, -- + tipd_DQ4 => VitalZeroDelay01, -- + tipd_DQ5 => VitalZeroDelay01, -- + tipd_DQ6 => VitalZeroDelay01, -- data + tipd_DQ7 => VitalZeroDelay01, -- lines + tipd_DQ8 => VitalZeroDelay01, -- + tipd_DQ9 => VitalZeroDelay01, -- + tipd_DQ10 => VitalZeroDelay01, -- + tipd_DQ11 => VitalZeroDelay01, -- + tipd_DQ12 => VitalZeroDelay01, -- + tipd_DQ13 => VitalZeroDelay01, -- + tipd_DQ14 => VitalZeroDelay01, -- + + tipd_DQ15 => VitalZeroDelay01, -- DQ15/A-1 + + tipd_CENeg => VitalZeroDelay01, + tipd_OENeg => VitalZeroDelay01, + tipd_WENeg => VitalZeroDelay01, + tipd_RESETNeg => VitalZeroDelay01, + tipd_WPNeg => VitalZeroDelay01,--WP#/ACC + tipd_BYTENeg => VitalZeroDelay01, + + -- tpd delays + tpd_A0_DQ0 => UnitDelay01,--tACC + tpd_A0_DQ1 => UnitDelay01,--tPACC + tpd_CENeg_DQ0 => UnitDelay01Z, + --(tCE,tCE,tDF,-,tDF + tpd_OENeg_DQ0 => UnitDelay01Z, + --(tOE,tOE,tDF,-,tDF + tpd_RESETNeg_DQ0 => UnitDelay01Z, + --(-,-,0,-,0,-) + tpd_CENeg_RY => UnitDelay01, --tBUSY + tpd_WENeg_RY => UnitDelay01, --tBUSY + + --tsetup values + tsetup_A0_CENeg => UnitDelay, --tAS edge \ + tsetup_A0_OENeg => UnitDelay, --tASO edge \ + tsetup_DQ0_CENeg => UnitDelay, --tDS edge / + + --thold values + thold_CENeg_RESETNeg=> UnitDelay, --tRH edge / + thold_OENeg_WENeg => UnitDelay, --tOEH edge / + thold_A0_CENeg => UnitDelay, --tAH edge \ + thold_A0_OENeg => UnitDelay, --tAHT edge \ + thold_DQ0_CENeg => UnitDelay, --tDH edge / + thold_WENeg_OENeg => UnitDelay, --tGHVL edge / + + --tpw values: pulse width + tpw_RESETNeg_negedge=> UnitDelay, --tRP + tpw_OENeg_posedge => UnitDelay, --tOEPH + tpw_WENeg_negedge => UnitDelay, --tWP + tpw_WENeg_posedge => UnitDelay, --tWPH + tpw_CENeg_negedge => UnitDelay, --tCP + tpw_CENeg_posedge => UnitDelay, --tCEPH + tpw_A0_negedge => UnitDelay, --tWC tRC + -- tdevice values: values for internal delays + --Effective Write Buffer Program Operation tWHWH1 + tdevice_WBPB => 11 us, + --Program Operation + tdevice_POB => 100 us, + --Sector Erase Operation tWHWH2 + tdevice_SEO => 500 ms, + --Timing Limit Exceeded + tdevice_HANG => 400 ms, --? + --program/erase suspend timeout + tdevice_START_T1 => 5 us, + --sector erase command sequence timeout + tdevice_CTMOUT => 50 us, + --device ready after Hardware reset(during embeded algorithm) + tdevice_READY => 20 us, --tReady + + -- generic control parameters + InstancePath => DefaultInstancePath, + TimingChecksOn => TRUE,--DefaultTimingChecks, + MsgOn => DefaultMsgOn, + XOn => DefaultXon, + -- memory file to be loaded + mem_file_name => mem_file, + prot_file_name => prot_file , + secsi_file_name => secsi_file, + + UserPreload => UserPreload, + LongTimming => LongTimming, + -- For FMF SDF technology file usage + TimingModel => "AM29LV640MH90R" -- TimingModel + ) + PORT MAP( + A21 => T_A(21), -- + A20 => T_A(20), -- + A19 => T_A(19), -- + A18 => T_A(18), -- + A17 => T_A(17), -- + A16 => T_A(16), -- + A15 => T_A(15), -- + A14 => T_A(14), -- + A13 => T_A(13), --address + A12 => T_A(12), --lines + A11 => T_A(11), -- + A10 => T_A(10), -- + A9 => T_A(9), -- + A8 => T_A(8), -- + A7 => T_A(7), -- + A6 => T_A(6), -- + A5 => T_A(5),-- + A4 => T_A(4),-- + A3 => T_A(3), -- + A2 => T_A(2), -- + A1 => T_A(1), -- + A0 => T_A(0), -- + + DQ15 => T_DQ(15), -- DQ15/A-1 + DQ14 => T_DQ(14), -- + DQ13 => T_DQ(13), -- + DQ12 => T_DQ(12), -- + DQ11 => T_DQ(11), -- + DQ10 => T_DQ(10), -- + DQ9 => T_DQ(9), -- data + DQ8 => T_DQ(8), -- lines + DQ7 => T_DQ(7), -- + DQ6 => T_DQ(6), -- + DQ5 => T_DQ(5), -- + DQ4 => T_DQ(4), -- + DQ3 => T_DQ(3), -- + DQ2 => T_DQ(2), -- + DQ1 => T_DQ(1), -- + DQ0 => T_DQ(0), -- + + CENeg => T_CENeg, + OENeg => T_OENeg, + WENeg => T_WENeg, + RESETNeg => T_RESETNeg, + WPNeg => T_WPNeg, --WP#/ACC + BYTENeg => T_BYTENeg, + RY => T_RY --RY/BY# + ); + + --------------------------------------------------------------------------- + --protected sector + --------------------------------------------------------------------------- + ProtSecNum <= SecNum WHEN TimingModel(11) = 'H' ELSE + 0 ;-- WHEN TimingModel = "AM29LV128ML93R" + + pwron <= '0', '1' after 1 ns; + +--At the end of the simulation, if ErrorInTest='0' there were no errors +err_ctrl : PROCESS ( check_err ) + BEGIN + IF check_err = '1' THEN + ErrorInTest <= '1'; + END IF; + END PROCESS err_ctrl; + +tb :PROCESS + + -------------------------------------------------------------------------- + --= PROCEDURE to select TC + -- can be modified to read TC list from file, or to generate random list + -------------------------------------------------------------------------- + PROCEDURE Pick_TC + (Model : IN STRING := "AM29LV640MH90R" ) + IS + BEGIN + IF TC_cnt < tc(TS_cnt) THEN + TC_cnt := TC_cnt+1; + ELSE + TC_cnt:=1; + IF TS_cnt<30 THEN + TS_cnt := TS_cnt+1; + ELSE + -- end test + IF ErrorInTest='0' THEN + REPORT "Test Ended without errors" + SEVERITY note; + ELSE + REPORT "There were errors in test" + SEVERITY note; + END IF; + WAIT; + END IF; + END IF; + END PROCEDURE Pick_TC; + + --------------------------------------------------------------------------- + --bus commands, device specific implementation + --------------------------------------------------------------------------- + TYPE bus_type IS (bus_idle, + bus_standby, --CE# deasseretd, others are don't care + bus_enable, --CE# asserted, others deasserted + bus_output_disable, + bus_reset, + bus_write, + bus_read); + + --bus drive for specific command sequence cycle + PROCEDURE bus_cycle( + bus_cmd :IN bus_type := bus_idle; + byte :IN boolean ; + data :IN INTEGER RANGE -2 TO MaxData := -2; -- -1 for all Z + dataHi :IN INTEGER RANGE -2 TO MaxData := -2; -- -2 for ignore + sector :IN INTEGER RANGE -1 TO SecNum := -1; -- -1 for ignore addr + address :IN NATURAL RANGE 0 TO SecSize := 0; + disable :IN boolean := false; + violate :IN boolean := false; + tm :IN TIME := 10 ns) + IS + + VARIABLE tmp : std_logic_vector(15 downto 0); + BEGIN + + IF data=-1 THEN -- HiZ + T_DQ(7 downto 0) <= (OTHERS => 'Z'); + END IF; + + IF (NOT byte)THEN --word access + IF dataHi=-1 THEN -- HiZ + T_DQ(15 downto 8) <= (OTHERS => 'Z'); + END IF; + T_BYTENeg <= '1'; + ELSE --byte access + T_BYTENeg <= '0'; + T_DQ(14 downto 8) <= (OTHERS => 'Z'); + END IF; + + IF sector > -1 THEN + T_A(HiAddrBit downto 15) <= to_slv(sector, HiAddrbit-14); + tmp := to_slv(address, 16); + IF byte THEN + T_A(14 downto 0) <= tmp(15 downto 1); + T_DQ(15) <= tmp(0); + ELSE + T_A(14 downto 0) <= tmp(14 downto 0); + END IF; + + END IF; + + wait for 1 ns; + + CASE bus_cmd IS + WHEN bus_output_disable => + T_OENeg <= '1'; + WAIT FOR 20 ns; + + WHEN bus_idle => + T_RESETNeg <= '1'; + T_WENeg <= '1'; + T_CENeg <= '1'; + T_OENeg <= '1'; + IF disable THEN + T_WPNeg <= '0'; + ELSE + T_WPNeg <= '1'; + END IF; + WAIT FOR 30 ns; + + WHEN bus_standby => + T_CENeg <= '1'; + WAIT FOR 30 ns; + + WHEN bus_reset => + T_RESETNeg <= '0', '1' AFTER tm ; + -- WAIT FOR 500 ns should follow this bus cmd for reset to + --complete + WAIT FOR 30 ns; + + WHEN bus_enable => + T_WENeg <= '1' AFTER 50 ns; --- + T_CENeg <= '0' AFTER 50 ns; --- + T_OENeg <= '1' AFTER 30 ns; --- + + WAIT FOR tm ; + + WHEN bus_write => + T_OENeg <= '1' ;-- AFTER 5 ns; + T_CENeg <= '0' AFTER 10 ns ; + T_WENeg <= '0' AFTER 20 ns; + + IF data>-1 THEN + T_DQ(7 downto 0) <= to_slv(data,8); + END IF; + IF NOT byte THEN + IF dataHi>-1 THEN + T_DQ(15 downto 8) <= to_slv(dataHi,8); + END IF; + END IF; + + IF violate THEN + T_WENeg <= '1'; + WAIT FOR 50 ns; + T_WENeg <= '0', '1' AFTER tm; + WAIT FOR 50 ns; + ELSE + WAIT FOR 100 ns; + END IF; + + WHEN bus_read => + + T_CENeg <= '0' ; + T_WENeg <= '1'AFTER 10 ns; + IF NOT disable THEN + T_OENeg <= '0' AFTER 15 ns; + ELSE + T_OENeg <= '1'; + END IF; + + IF NOT byte THEN + T_DQ(15 downto 8) <= (OTHERS => 'Z'); + END IF; + T_DQ(7 downto 0) <= (OTHERS => 'Z'); + + WAIT FOR 100 ns; + + -- T_OENeg <= '1' ; ----------- + + END CASE; + + + END PROCEDURE; + + + --------------------------------------------------------------------------- + --procedure to decode commands into specific bus command sequence + --------------------------------------------------------------------------- + PROCEDURE cmd_dc + ( command : IN cmd_rec ) + IS + VARIABLE D_hi : NATURAL ;--RANGE 0 to MaxData; + VARIABLE D_lo : NATURAL RANGE 0 to MaxData; + VARIABLE Addr : NATURAL RANGE 0 to SecSize :=0; + VARIABLE Addrfix : NATURAL RANGE 0 to SecSize/2:=0; + VARIABLE Sect : INTEGER RANGE -1 to SecNum :=0; + VARIABLE slv_1, slv_2 : std_logic_vector(7 downto 0); + VARIABLE byte : boolean; + VARIABLE i : NATURAL; + BEGIN + CASE command.cmd IS + WHEN idle => + bus_cycle(bus_cmd => bus_idle, + byte => command.byte, + disable => command.aux=disable); + + WHEN h_reset => + bus_cycle(bus_cmd => bus_reset, + byte => command.byte, + tm => command.wtime); + + WHEN rd => + bus_cycle(bus_cmd => bus_enable, + byte => command.byte, + data => -1, + sector => command.sect, + address => command.addr, + tm => 90 ns); + + bus_cycle(bus_cmd => bus_read, + byte => command.byte, + data => -1, + dataHi => -1, + sector => command.sect, + address => command.addr, + disable => command.aux=disable); + + bus_cycle(bus_cmd => bus_output_disable, + byte => command.byte); + + WHEN rd_page => + bus_cycle(bus_cmd => bus_enable, + byte => command.byte, + data => -1, + sector => 0, + address => 0, + tm => 90 ns); + + Addr := command.addr; + Sect := command.sect; + byte := command.byte; + ---- 08July---- + WAIT FOR 10 ns; + -------------- + i := 0; + WHILE i < command.d_hi LOOP + + IF command.wtime > 0 ns THEN + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + --byte toggle mode + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + byte := false; + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + Addrfix := Addr /2; + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + --word read; + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addrfix); + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 10 ns); + byte := true; + bus_cycle(bus_cmd => bus_enable, + byte => byte, + data => -1, + sector => -1, + tm => 30 ns); + + --first byte read + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addr); + + bus_cycle(bus_cmd => bus_output_disable, ---- + byte => byte); ---- + + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + i := i +3; + wait for 10 ns; ------- + ELSE + byte := command.byte; + END IF; + --second byte read in byte toggle mode + bus_cycle(bus_cmd => bus_read, + byte => byte, + data => -1, + dataHi => -1, + sector => Sect, + address => Addr); + + + IF Addr < SecSize THEN + Addr := Addr+1; + ELSE + Addr := 0; + IF Sect < SecNum THEN + Sect := Sect+1; + ELSE + REPORT "No more locations to read !!!" + SEVERITY warning; + END IF; + END IF; + i := i +1; + WAIT FOR 10 ns; + END LOOP; + bus_cycle(bus_cmd => bus_output_disable, + byte => command.byte); + + + + WHEN w_cycle => + + D_lo := 16#AA# ; --first command data + Addr := 16#AAA#; --first command byte address + D_hi := 16#55#; --second command data + Addrfix := 16#555#; --second command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + Addrfix := 16#2AA#; --second command byte address + END IF; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_lo, + dataHi => 0, + sector => 0, + address => Addr, + violate => command.aux=violate, + tm => command.wtime); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_hi, + dataHi => 0, + sector => 0, + address => Addrfix); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_reset | w_prog | w_erase | w_unlock | + w_autoselect | w_enter_sec => + Addr := 16#AAA#; + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + + CASE command.cmd IS + WHEN w_reset => + d_lo := 16#F0#; + WHEN w_prog => + d_lo := 16#A0#; + WHEN w_erase => + d_lo := 16#80#; + WHEN w_unlock => + d_lo := 16#20#; + WHEN w_autoselect => + d_lo := 16#90#; + WHEN w_enter_sec => + d_lo := 16#88#; + WHEN OTHERS => + d_lo := 0; + END CASE; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => d_lo, + dataHi => 0, + sector => 0, + address => Addr); + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + + WHEN w_unlock_reset => + Addr := 16#AAA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#90#, + dataHi => 0, + sector => 0, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#F0#, + dataHi => 0, + sector => 0, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + WHEN w_chip_ers => + Addr := 16#AAA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#555#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#10#, + dataHi => 0, + sector => 0, + Address => Addr); + FOR i IN 0 TO SecNum LOOP + IF Sec_Prot(i)/='1' THEN + mem(i) := (OTHERS=>16#FF#); + END IF; + END LOOP; + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_cfi => + Addr := 16#AA#; --first command byte address + IF NOT command.byte THEN + --if word addressing + Addr := 16#55#; --first command byte address + END IF; + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#98#, + dataHi => 0, + sector => 0, + Address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + + WHEN w_suspend => + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#B0#, + dataHi => 0, + sector => -1); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + WHEN w_resume => + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => 16#30#, + dataHi => 0, + sector => -1); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + WHEN w_data => + + D_hi := command.d_hi MOD 16#100#; + D_lo := command.d_lo ; + Addr := command.addr; + Sect := command.sect; + + bus_cycle(bus_cmd => bus_write, + byte => command.byte, + data => D_lo, + dataHi => D_hi, + sector => Sect, + address => Addr); + + bus_cycle(bus_cmd => bus_standby, + byte => command.byte); + + + IF NOT command.byte THEN + Addr := Addr*2; + END IF; + + --write value(s) in default mem + IF status = erase_active AND Sec_Prot(Sect)/='1'THEN + --sector should be erased + mem(Sect) := (OTHERS=>16#FF#); + + ELSIF status = erase_na AND Sec_Prot(Sect)/='1'THEN + --sector erase terminated = data integrity violated + mem(Sect) := (OTHERS=>-1); + + ELSIF status = readX AND Sec_Prot(Sect)/='1' THEN + mem(Sect)(Addr) := -1; + IF NOT command.byte THEN + mem(Sect)(Addr+1) := -1; + END IF; + + -- Write to Secure Silicon Sector Region + ELSIF status = rd_SecSi AND FactoryProt/='1' THEN + slv_1 := to_slv(d_lo,8); + IF SecSi(Addr)>-1 THEN + slv_2 := to_slv(SecSi(Addr),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + SecSi(Addr) := to_nat(slv_1); + IF NOT command.byte THEN + slv_1 := to_slv(d_hi,8); + IF SecSi(Addr+1)>-1 THEN + slv_2 := to_slv(SecSi(Addr+1),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + SecSi(Addr+1) := to_nat(slv_1); + END IF; + + ELSIF status=buff_wr_busy THEN + --Write to Buffer command cycle + null; + + ELSIF status=erase_na THEN + --sector erase command sequence violation + null; + + -- Write to Flash Memory Array + ELSIF status /= err AND Sec_Prot(Sect)/='1'THEN + slv_1 := to_slv(d_lo,8); + IF mem(Sect)(Addr)>-1 THEN + slv_2 := to_slv(mem(Sect)(Addr),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + mem(Sect)(Addr) := to_nat(slv_1); + IF NOT command.byte THEN + slv_1 := to_slv(d_hi,8); + IF mem(Sect)(Addr+1)>-1 THEN + slv_2 := to_slv(mem(Sect)(Addr+1),8); + ELSE + slv_2 := (OTHERS=>'X'); + END IF; + FOR i IN 0 to 7 LOOP + IF slv_2(i)='0' THEN + slv_1(i):='0'; + END IF; + END LOOP; + mem(Sect)(Addr+1) := to_nat(slv_1); + END IF; + END IF; + + + WHEN wt => + WAIT FOR command.wtime; + + WHEN wt_rdy => + IF T_RY/='1' THEN + WAIT UNTIL rising_edge(T_RY) FOR command.wtime; + END IF; + + WHEN wt_bsy => + IF T_RY='1' THEN + WAIT UNTIL falling_edge(T_RY) FOR command.wtime; + END IF; + + WHEN OTHERS => null; + END CASE; + END PROCEDURE; + + + VARIABLE cmd_cnt : NATURAL; + VARIABLE command : cmd_rec; -- + +BEGIN + Pick_TC (Model => "AM29LV640MH90R" ); + + Tseries <= ts_cnt ; + Tcase <= tc_cnt ; + + Generate_TC + (Model => "AM29LV640MH90R" , + Series => ts_cnt, + TestCase => tc_cnt, + command_seq => cmd_seq); + + + cmd_cnt := 1; + WHILE cmd_seq(cmd_cnt).cmd/=done LOOP + command:= cmd_seq(cmd_cnt); + IF command.sect = -1 THEN + command.sect := ProtSecNum; + END IF; + status <= command.status; + sts_check<= to_slv(command.d_lo,8); --used only for toggle/status check + cmd_dc(command); + cmd_cnt :=cmd_cnt +1; + + END LOOP; + +END PROCESS tb; + +--process to monitor WP# +PROCESS(T_WPNeg) +VARIABLE reg : std_logic; +BEGIN + IF falling_edge(T_WPNeg) THEN + reg := Sec_Prot(ProtSecNum); + Sec_Prot(ProtSecNum) := '1'; + ELSIF rising_edge(T_WPNeg) THEN + Sec_Prot(ProtSecNum) := reg; + END IF; +END PROCESS; + +-------------------------------------------------------------------------------- +-- Checker process, +-- Bus transition extractor: when bus cycle is read samples addr and data +-- Transition checker : verifies correct read data using default memory +-------------------------------------------------------------------------------- +checker: PROCESS + VARIABLE RAddr : NATURAL; + VARIABLE RSect : NATURAL; + VARIABLE longread : boolean; + VARIABLE shortread : boolean; + VARIABLE toggle : boolean:=false; + VARIABLE toggle_sts : std_logic_vector(7 downto 0); + +BEGIN +-- Transition extractor + IF (T_CENeg='0'AND T_OENeg='0'AND T_WENeg='1') THEN + IF T_BYTENeg='1' THEN + RAddr := to_nat(T_A(14 downto 0)&'0'); + ELSE + RAddr := to_nat(T_A(14 downto 0)&T_DQ(15)); + END IF; + RSect := to_nat(T_A(HiAddrBit downto 15)); + + shortread:= false; + longread := false; + + --DUT specific timing + IF (T_CENeg'EVENT OR T_WENeg'EVENT OR T_A(HiAddrBit downto 2)'EVENT)AND -- + (status=read OR status=rd_cfi OR status=rd_secsi) THEN --OR status=readX) + longread := true; + CASE TimingModel IS + WHEN "AM29LV640MH90R" | + "AM29LV640ML90R" => WAIT FOR 95 ns; +-- WHEN "AM29LV640MH101" | +-- "AM29LV640ML101" => WAIT FOR 105 ns; +-- WHEN "AM29LV640MH101R" | +-- "AM29LV640ML101R" => WAIT FOR 105 ns; +-- WHEN "AM29LV640MH112" | +-- "AM29LV640ML112" => WAIT FOR 115 ns; +-- WHEN "AM29LV640MH112R" | +-- "AM29LV640ML112R" => WAIT FOR 115 ns; +-- WHEN "AM29LV640MH120" | +-- "AM29LV640ML120" => WAIT FOR 125 ns; +-- WHEN "AM29LV640MH120R" | +-- "AM29LV640ML120R" => WAIT FOR 125 ns; + WHEN OTHERS => + REPORT "Timing model NOT supported : "&TimingModel + SEVERITY error; + END CASE; + + ELSIF T_A(1 downto 0)'EVENT OR + (T_DQ(15)'EVENT AND T_BYTENeg='0')OR + (T_BYTENeg'EVENT) OR + T_OENeg'EVENT OR + (status/=read AND status/=rd_cfi AND + status/=rd_secsi) THEN --AND status/=readX) + shortread:=true; + CASE TimingModel IS + WHEN "AM29LV640MH90R" | + "AM29LV640ML90R" => WAIT FOR 30 ns; +-- WHEN "AM29LV640MH101" | +-- "AM29LV640ML101" => WAIT FOR 40 ns; +-- WHEN "AM29LV640MH101R" | +-- "AM29LV640ML101R" => WAIT FOR 40 ns; +-- WHEN "AM29LV640MH112" | +-- "AM29LV640ML112" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH112R" | +-- "AM29LV640ML112R" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH120" | +-- "AM29LV640ML120" => WAIT FOR 45 ns; +-- WHEN "AM29LV640MH120R" | +-- "AM29LV640ML120R" => WAIT FOR 45 ns; + WHEN OTHERS => + REPORT "Timing model NOT supported : "&TimingModel + SEVERITY error; + END CASE; + + END IF; + + + + --Checker + IF longread OR shortread THEN + + CASE status IS + WHEN none => + toggle := false; + + -- read memory array data + WHEN read => + toggle := false; + Check_read ( + DQ => T_DQ, + D_lo => mem(RSect)(RAddr), + D_hi => mem(RSect)(RAddr+1), + Byte => T_BYTENeg, + check_err=> check_err); + + -- read secure silicon region + WHEN rd_secsi => + toggle := false; + Check_SecSi ( + DQ => T_DQ, + D_lo => SecSi(RAddr), + D_hi => SecSi(RAddr+1), + Byte => T_BYTENeg, + check_err=>check_err); + + + --read CFI query codes + WHEN rd_cfi => + RAddr := to_nat(T_A(14 downto 0)); --x16 addressing + toggle := false; + Check_CFI ( + DQ => T_DQ, + D_lo => CFI_array(RAddr) , + D_hi => 0 , + Byte => T_BYTENeg, + check_err=>check_err); + + + + -- read Autoselect codes + WHEN rd_AS => + RAddr := to_nat(T_A(14 downto 0)); --x16 addressing + toggle := false; + Check_AS ( + DQ => T_DQ, + addr => RAddr, + ProtSecNum=>ProtSecNum, + secProt => Sec_Prot(RSect), + FactoryProt=>FactoryProt , + Byte => T_BYTENeg, + AS_E => to_slv(16#0C#,8), + AS_F => to_slv(1,8), + + check_err=>check_err); + + + WHEN rd_HiZ => + toggle:=false; + Check_Z ( + DQ => T_DQ, + check_err=>check_err); + + + + WHEN readX => + toggle:=false; + Check_X ( + DQ => T_DQ, + check_err=>check_err); + + + WHEN erase_na | erase_active => + IF toggle THEN + Check_Erase ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN ers_susp_e => + IF toggle THEN + Check_Ers_Susp ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + +-- + + WHEN ers_susp_prog_na | ers_susp_prog => + IF toggle THEN + Check_Ers_Susp_Prog ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + +-- + + WHEN prog_na | prog_active => + IF toggle THEN + Check_Progr ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN buff_wr_busy | buff_wr_N_busy => + IF toggle THEN + Check_Buff_Busy ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + + WHEN buff_abort => + IF toggle THEN + Check_Abort ( + DQ => T_DQ(7 downto 0), + sts => status, + toggle => toggle_sts, + sts_check=>sts_check, + RY => T_RY, + check_err=>check_err); + + toggle_sts := T_DQ(7 downto 0); --update toggle check + END IF; + WHEN OTHERS => null; + END CASE; + + -- get firs data for toggle check + CASE status IS + WHEN prog_active | prog_na | + erase_active | erase_na | + ers_susp_e | + ers_susp_prog | ers_susp_prog_na | + buff_wr_busy | buff_wr_N_busy | + buff_abort | get_toggle => + + IF (NOT toggle) OR (status=get_toggle) THEN + toggle:=true; + toggle_sts := T_DQ(7 downto 0); + END IF; + + WHEN OTHERS => null; + END CASE; + + + END IF; + + END IF; + + WAIT ON T_A, T_CENeg, T_OENeg, T_WENeg, T_DQ(15), T_BYTENeg; + +END PROCESS checker; + + +default: PROCESS + -- text file input variables + FILE mem_f : text is mem_file; + FILE prot_f : text is prot_file; + FILE secsi_f : text is secsi_file; + + VARIABLE S_ind : NATURAL RANGE 0 TO SecNum:= 0; + VARIABLE ind : NATURAL RANGE 0 TO SecSize:= 0; + VARIABLE buf : line; + +BEGIN + --Preload Control + ----------------------------------------------------------------------- + -- File Read Section + ----------------------------------------------------------------------- + IF UserPreload THEN + --- Sector protection preload + IF (prot_file /= "none" ) THEN + ind := 0; + FactoryProt := '0'; + Sec_Prot := (OTHERS => '0'); + WHILE (not ENDFILE (prot_f)) LOOP + READLINE (prot_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 3)); --address + ELSE + IF ind > SecNum THEN + --SecSi Factory protect preload + IF buf(1)='1' THEN + FactoryProt := '1'; + END IF; + ELSE + -- Standard Sector prload + IF buf(1)='1' THEN + Sec_Prot(ind):= '1'; + END IF; + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + -- Secure Silicon Sector Region preload + IF (SecSi_file /= "none" ) THEN + SecSi := (OTHERS => MaxData); + ind := 0; + WHILE (not ENDFILE (SecSi_f)) LOOP + READLINE (SecSi_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 3)); --address + ELSE + IF ind <= SecSiSize THEN + SecSi(ind) := h(buf(1 TO 2)); + ind := ind + 1; + END IF; + END IF; + END LOOP; + END IF; + + --- Memory Preload + IF (mem_file /= "none" ) THEN + ind := 0; + Mem := (OTHERS => (OTHERS => MaxData)); + -- load sector 0 + WHILE (not ENDFILE (mem_f)) LOOP + READLINE (mem_f, buf); + IF buf(1) = '/' THEN + NEXT; + ELSIF buf(1) = '@' THEN + ind := h(buf(2 to 5)); --address + ELSE + IF ind <= SecSize THEN + Mem(0)(ind) := h(buf(1 to 2)); + ind := ind + 1; + END IF; + END IF; + END LOOP; + -- load other sectors + FOR i IN 1 TO SecNum LOOP + Mem(i) := Mem(0); + END LOOP; + END IF; + + END IF; + ----------------------------------------------------------------------- + --CFI array data / AM29LV640MH90R !!! DEVICE SPECIFIC + ----------------------------------------------------------------------- + --CFI query identification string + -- !!!!!! WORD ADDRESSES (x16) - for x8 addressing double addr + --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#; + --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#07#; + CFI_array(16#20#) := 16#07#; + CFI_array(16#21#) := 16#0A#; + CFI_array(16#22#) := 16#00#; + CFI_array(16#23#) := 16#01#; + CFI_array(16#24#) := 16#05#; + CFI_array(16#25#) := 16#04#; + CFI_array(16#26#) := 16#00#; + --device geometry definition + CFI_array(16#27#) := 16#17#; + CFI_array(16#28#) := 16#02#; + CFI_array(16#29#) := 16#00#; + CFI_array(16#2A#) := 16#05#; + CFI_array(16#2B#) := 16#00#; + CFI_array(16#2C#) := 16#01#; + CFI_array(16#2D#) := 16#7F#; + CFI_array(16#2E#) := 16#00#; + CFI_array(16#2F#) := 16#00#; + CFI_array(16#30#) := 16#01#; + CFI_array(16#31#) := 16#00#; + CFI_array(16#32#) := 16#00#; + CFI_array(16#33#) := 16#00#; + CFI_array(16#34#) := 16#00#; + 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#; + --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#08#; + CFI_array(16#46#) := 16#02#; + CFI_array(16#47#) := 16#01#; + CFI_array(16#48#) := 16#01#; + CFI_array(16#49#) := 16#04#; + CFI_array(16#4A#) := 16#00#; + CFI_array(16#4B#) := 16#00#; + CFI_array(16#4C#) := 16#01#; + CFI_array(16#4D#) := 16#B5#; + CFI_array(16#4E#) := 16#C5#; + IF TimingModel(11) = 'L' THEN + CFI_array(16#4F#) := 16#04#; + ELSE + CFI_array(16#4F#) := 16#05#; --uniform sectors top protect + END IF; + CFI_array(16#50#) := 16#01#; + + WAIT; + +END PROCESS default; + + + +END vhdl_behavioral; + diff --git a/lib/models/memory/flash/serial/S25fl032p/utilities/conversions.vhd b/lib/models/memory/flash/serial/S25fl032p/utilities/conversions.vhd new file mode 100644 index 0000000..e5fc0d6 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl032p/utilities/conversions.vhd @@ -0,0 +1,1035 @@ +-------------------------------------------------------------------------------- +-- File Name: conversions_p.vhd +-------------------------------------------------------------------------------- +-- Copyright (C) 1997, 1998, 2001 Free Model Foundry; http://eda.org/fmf/ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License version 2 as +-- published by the Free Software Foundation. +-- +-- This package was written by SEVA Technologies, Inc. and donated to the FMF. +-- www.seva.com +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Steele 97 DEC 05 Added header and formatting to SEVA file +-- V1.1 R. Munden 98 NOV 28 Corrected some comments +-- Corrected function b +-- V1.2 R. Munden 01 MAY 27 Corrected function to_nat for weak values +-- and combined into a single file +-- +-------------------------------------------------------------------------------- + +LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; + +-------------------------------------------------------------------------------- +-- CONVERSION FUNCTION SELECTION TABLES +-------------------------------------------------------------------------------- +-- +-- FROM TO: std_logic_vector std_logic natural time string +-- -----------------|---------------|---------|---------|---------|----------- +-- std_logic_vector | N/A | N/A | to_nat | combine | see below +-- std_logic | N/A | N/A | to_nat | combine | see below +-- natural | to_slv | to_sl | N/A | to_time | see below +-- time | N/A | N/A | to_nat | N/A | to_time_str +-- hex string | h | N/A | h | combine | N/A +-- decimal string | d | N/A | d | combine | N/A +-- octal string | o | N/A | o | combine | N/A +-- binary string | b | N/A | b | combine | N/A +-- -----------------|---------------|---------|---------|---------|----------- +-- +-- FROM TO: hex string decimal string octal string binary string +-- -----------------|------------|-------------|------------|---------------- +-- std_logic_vector | to_hex_str | to_int_str | to_oct_str | to_bin_str +-- std_logic | N/A | N/A | N/A | to_bin_str +-- natural | to_hex_str | to_int_str | to_oct_str | to_bin_str +-- -----------------|------------|-------------|------------|---------------- +-- +-------------------------------------------------------------------------------- + +PACKAGE conversions IS + + ---------------------------------------------------------------------------- + -- the conversions in this package are not guaranteed to be synthesizable. + -- + -- others functions available + -- fill creates a variable length string of the fill character + -- + -- + -- + -- input parameters of type natural or integer can be in the form: + -- normal -> 8, 99, 4_237 + -- base#value# -> 2#0101#, 16#fa4C#, 8#6_734# + -- with exponents(x10) -> 8e4, 16#2e#E4 + -- + -- input parameters of type string can be in the form: + -- "99", "4_237", "0101", "1010_1010" + -- + -- for bit/bit_vector <-> std_logic/std_logic_vector conversions use + -- package std_logic_1164 + -- to_bit(std_logic) + -- to_bitvector(std_logic_vector) + -- to_stdlogic(bit) + -- to_stdlogicvector(bit_vector) + -- + -- for "synthesizable" signed/unsigned/std_logic_vector/integer + -- conversions use + -- package std_logic_arith + -- conv_integer(signed/unsigned) + -- conv_unsigned(integer/signed,size) + -- conv_signed(integer/unsigned,size) + -- conv_std_logic_vector(integer/signed/unsigned,size) + -- + -- for "synthesizable" std_logic_vector -> integer conversions use + -- package std_logic_unsigned/std_logic_signed + -- + -- conv_integer(std_logic_vector) + -- + -- type1'(expression of type2) + -- + -- most conversions have 4 parmeters: + -- x : value to be converted + -- rtn_len : size of the return value + -- justify : justify value 'left' or 'right', default is right + -- basespec : print the base of the value - 'yes'/'no', default is yes + -- + -- Typical ways to call these functions: + -- simple, all defaults used + -- to_bin_str(x) + -- x will be converted to a string of minimum size with a + -- base specification appended for clarity + -- if x is 10101 then return is b"10101" + -- + -- to control size of return string + -- to_hex_str(x, + -- 6) + -- length of string returned will be 6 characters + -- value will be right justified in the field + -- if x is 10101 then return is ....h"15" + -- where '.' represents a blank + -- if 'rtn_len' parm defaults or is set to 0 then + -- return string will always be minimum size + -- + -- to left justify and suppress base specification + -- to_int_str(x, + -- 6, + -- justify => left, + -- basespec => yes) + -- length of return string will be 6 characters + -- the base specification will be suppressed + -- if x is 10101 then return is 21.... + -- where '.' represents a blank + -- + -- other usage notes + -- + -- if rtn_len less than or equal to x'length then ignore + -- rtn_len and return string of x'length + -- the 'justify' parm is effectively ignored in this case + -- + -- if rtn_len greater than x'length then return string + -- of rtn_len with blanks based on 'justify' parm + -- + -- these routines do not handle negative numbers + ---------------------------------------------------------------------------- + + type justify_side is (left, right); + type b_spec is (no , yes); + + -- std_logic_vector to binary string + function to_bin_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- std_logic to binary string + function to_bin_str(x : std_logic; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to binary string + function to_bin_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to hex string + function to_hex_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to hex string + function to_hex_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to octal string + function to_oct_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- natural to octal string + function to_oct_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- natural to integer string + function to_int_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + -- see note above regarding possible formats for x + + -- std_logic_vector to integer string + function to_int_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string; + + -- time to string + function to_time_str (x : time) + return string; + + -- add characters to a string + function fill (fill_char : character := '*'; + rtn_len : integer := 1) + return string; + -- usage: + -- fill + -- returns * + -- fill(' ',10) + -- returns .......... when '.' represents a blank + -- fill(lf) or fill(ht) + -- returns line feed character or tab character respectively + + -- std_logic_vector to natural + function to_nat (x : std_logic_vector) + return natural; + + -- std_logic to natural + function to_nat (x : std_logic) + return natural; + + -- time to natural + function to_nat (x : time) + return natural; + + -- hex string to std_logic_vector + function h (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or a,A to f,F + -- or x,X,z,Z,u,U,-,w,W, result will be 0 + + -- decimal string to std_logic_vector + function d (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- octal string to std_logic_vector + function o (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 7 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- binary string to std_logic_vector + function b (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 1 or x,X,z,Z,u,U,-,w,W, + -- result will be 0 + + -- hex string to natural + function h (x : string) + return natural; + -- if x is other than characters 0 to 9 or a,A to f,F, result will be 0 + + -- decimal string to natural + function d (x : string) + return natural; + -- if x is other than characters 0 to 9, result will be 0 + + -- octal string to natural + function o (x : string) + return natural; + -- if x is other than characters 0 to 7, result will be 0 + + -- binary string to natural + function b (x : string) + return natural; + -- if x is other than characters 0 to 1, result will be 0 + + -- natural to std_logic_vector + function to_slv (x : natural; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector; + -- if rtn_len is < than sizeof(x), result will be truncated on the left + -- see note above regarding possible formats for x + + -- natural to std_logic + function to_sl (x : natural) + return std_logic; + + -- natural to time + function to_time (x : natural) + return time; + -- see note above regarding possible formats for x + +END conversions; +-- +-------------------------------------------------------------------------------- +-- + +PACKAGE BODY conversions IS + + -- private declarations for this package + type basetype is (binary, octal, decimal, hex); + + function max(x,y: integer) return integer is + begin + if x > y then return x; else return y; end if; + end max; + + function min(x,y: integer) return integer is + begin + if x < y then return x; else return y; end if; + end min; + + -- consider function sizeof for string/slv/???, return natural + + -- function size(len: natural) return natural is + -- begin + -- if len=0 then + -- return 31; + -- else return len; + -- end if; + -- end size; + + function nextmultof (x : positive; + size : positive) return positive is + begin + case x mod size is + when 0 => return size * x/size; + when others => return size * (x/size + 1); + end case; + end nextmultof; + + function rtn_base (base : basetype) return character is + begin + case base is + when binary => return 'b'; + when octal => return 'o'; + when decimal => return 'd'; + when hex => return 'h'; + end case; + end rtn_base; + + function format (r : string; + base : basetype; + rtn_len : natural ; + justify : justify_side; + basespec : b_spec) return string is + variable int_rtn_len : integer; + begin + if basespec=yes then + int_rtn_len := rtn_len - 3; + else + int_rtn_len := rtn_len; + end if; + if int_rtn_len <= r'length then + case basespec is + when no => return r ; + when yes => return rtn_base(base) & '"' & r & '"'; + end case; + else + case justify is + when left => + case basespec is + when no => + return r & fill(' ',int_rtn_len - r'length); + when yes => + return rtn_base(base) & '"' & r & '"' & + fill(' ',int_rtn_len - r'length); + end case; + when right => + case basespec is + when no => + return fill(' ',int_rtn_len - r'length) & r ; + when yes => + return fill(' ',int_rtn_len - r'length) & + rtn_base(base) & '"' & r & '"'; + end case; + end case; + end if; + end format; + + -- convert numeric string of any base to natural + function cnvt_base (x : string; + inbase : natural range 2 to 16) return natural is + -- assumes x is an unsigned number string of base 'inbase' + -- values larger than natural'high are not supported + variable r,t : natural := 0; + variable place : positive := 1; + begin + for i in x'reverse_range loop + case x(i) is + when '0' => t := 0; + when '1' => t := 1; + when '2' => t := 2; + when '3' => t := 3; + when '4' => t := 4; + when '5' => t := 5; + when '6' => t := 6; + when '7' => t := 7; + when '8' => t := 8; + when '9' => t := 9; + when 'a'|'A' => t := 10; + when 'b'|'B' => t := 11; + when 'c'|'C' => t := 12; + when 'd'|'D' => t := 13; + when 'e'|'E' => t := 14; + when 'f'|'F' => t := 15; + when '_' => t := 0; -- ignore these characters + place := place / inbase; + when others => + assert false + report lf & + "CNVT_BASE found input value larger than base: " & lf & + "Input value: " & x(i) & + " Base: " & to_int_str(inbase) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + if t / inbase > 1 then -- invalid value for base + assert false + report lf & + "CNVT_BASE found input value larger than base: " & lf & + "Input value: " & x(i) & + " Base: " & to_int_str(inbase) & lf & + "converting input to integer 0" + severity warning; + return 0; + else + r := r + (t * place); + place := place * inbase; + end if; + end loop; + return r; + end cnvt_base; + + function extend (x : std_logic; + len : positive) return std_logic_vector is + variable v : std_logic_vector(1 to len) := (others => x); + begin + return v; + end extend; + + + -- implementation of public declarations + + function to_bin_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + + variable int : std_logic_vector(1 to x'length):=x; + variable r : string(1 to x'length):=(others=>'$'); + begin + for i in int'range loop + r(i to i) := to_bin_str(int(i),basespec=>no); + end loop; + return format (r,binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_bin_str(x : std_logic; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable r : string(1 to 1); + begin + case x is + when '0' => r(1) := '0'; + when '1' => r(1) := '1'; + when 'U' => r(1) := 'U'; + when 'X' => r(1) := 'X'; + when 'Z' => r(1) := 'Z'; + when 'W' => r(1) := 'W'; + when 'H' => r(1) := 'H'; + when 'L' => r(1) := 'L'; + when '-' => r(1) := '-'; + end case; + return format (r,binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_bin_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 2 to 32 := 32; + variable r : string(2 to 32):=(others=>'$'); + begin + if int = 0 then + return format ("0",binary,rtn_len,justify,basespec); + end if; + + while int > 0 loop + case int rem 2 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when others => + assert false report lf & "TO_BIN_STR, shouldn't happen" + severity failure; + return "$"; + null; + end case; + int := int / 2; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 32),binary,rtn_len,justify,basespec); + end to_bin_str; + + function to_hex_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + -- will return x'length/4 + variable nxt : positive := nextmultof(x'length,4); + variable int : std_logic_vector(1 to nxt):= (others => '0'); + variable ptr : positive range 1 to (nxt/4)+1 := 1; + variable r : string(1 to nxt/4):=(others=>'$'); + subtype slv4 is std_logic_vector(1 to 4); + begin + int(nxt-x'length+1 to nxt) := x; + if nxt-x'length > 0 and x(x'left) /= '1' then + int(1 to nxt-x'length) := extend(x(x'left),nxt-x'length); + end if; + for i in int'range loop + next when i rem 4 /= 1; + case slv4'(int(i to i+3)) is + when "0000" => r(ptr) := '0'; + when "0001" => r(ptr) := '1'; + when "0010" => r(ptr) := '2'; + when "0011" => r(ptr) := '3'; + when "0100" => r(ptr) := '4'; + when "0101" => r(ptr) := '5'; + when "0110" => r(ptr) := '6'; + when "0111" => r(ptr) := '7'; + when "1000" => r(ptr) := '8'; + when "1001" => r(ptr) := '9'; + when "1010" => r(ptr) := 'A'; + when "1011" => r(ptr) := 'B'; + when "1100" => r(ptr) := 'C'; + when "1101" => r(ptr) := 'D'; + when "1110" => r(ptr) := 'E'; + when "1111" => r(ptr) := 'F'; + when "ZZZZ" => r(ptr) := 'Z'; + when "WWWW" => r(ptr) := 'W'; + when "LLLL" => r(ptr) := 'L'; + when "HHHH" => r(ptr) := 'H'; + when "UUUU" => r(ptr) := 'U'; + when "XXXX" => r(ptr) := 'X'; + when "----" => r(ptr) := '-'; + when others => + assert false + report lf & + "TO_HEX_STR found illegal value: " & + to_bin_str(int(i to i+3)) & lf & + "converting input to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr + 1; + end loop; + return format (r,hex,rtn_len,justify,basespec); + end to_hex_str; + + function to_hex_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 20 := 20; + variable r : string(1 to 20):=(others=>'$'); + begin + if x=0 then return format ("0",hex,rtn_len,justify,basespec); end if; + while int > 0 loop + case int rem 16 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when 8 => r(ptr) := '8'; + when 9 => r(ptr) := '9'; + when 10 => r(ptr) := 'A'; + when 11 => r(ptr) := 'B'; + when 12 => r(ptr) := 'C'; + when 13 => r(ptr) := 'D'; + when 14 => r(ptr) := 'E'; + when 15 => r(ptr) := 'F'; + when others => + assert false report lf & "TO_HEX_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 16; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 20),hex,rtn_len,justify,basespec); + end to_hex_str; + + function to_oct_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + -- will return x'length/3 + variable nxt : positive := nextmultof(x'length,3); + variable int : std_logic_vector(1 to nxt):= (others => '0'); + variable ptr : positive range 1 to (nxt/3)+1 := 1; + variable r : string(1 to nxt/3):=(others=>'$'); + subtype slv3 is std_logic_vector(1 to 3); + begin + int(nxt-x'length+1 to nxt) := x; + if nxt-x'length > 0 and x(x'left) /= '1' then + int(1 to nxt-x'length) := extend(x(x'left),nxt-x'length); + end if; + for i in int'range loop + next when i rem 3 /= 1; + case slv3'(int(i to i+2)) is + when "000" => r(ptr) := '0'; + when "001" => r(ptr) := '1'; + when "010" => r(ptr) := '2'; + when "011" => r(ptr) := '3'; + when "100" => r(ptr) := '4'; + when "101" => r(ptr) := '5'; + when "110" => r(ptr) := '6'; + when "111" => r(ptr) := '7'; + when "ZZZ" => r(ptr) := 'Z'; + when "WWW" => r(ptr) := 'W'; + when "LLL" => r(ptr) := 'L'; + when "HHH" => r(ptr) := 'H'; + when "UUU" => r(ptr) := 'U'; + when "XXX" => r(ptr) := 'X'; + when "---" => r(ptr) := '-'; + when others => + assert false + report lf & + "TO_OCT_STR found illegal value: " & + to_bin_str(int(i to i+2)) & lf & + "converting input to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr + 1; + end loop; + return format (r,octal,rtn_len,justify,basespec); + end to_oct_str; + + function to_oct_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 20 := 20; + variable r : string(1 to 20):=(others=>'$'); + begin + if x=0 then return format ("0",octal,rtn_len,justify,basespec); end if; + while int > 0 loop + case int rem 8 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when others => + assert false report lf & "TO_OCT_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 8; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 20),octal,rtn_len,justify,basespec); + end to_oct_str; + + function to_int_str(x : natural; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) return string is + variable int : natural := x; + variable ptr : positive range 1 to 32 := 32; + variable r : string(1 to 32):=(others=>'$'); + begin + if x=0 then return format ("0",hex,rtn_len,justify,basespec); + else + while int > 0 loop + case int rem 10 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when 2 => r(ptr) := '2'; + when 3 => r(ptr) := '3'; + when 4 => r(ptr) := '4'; + when 5 => r(ptr) := '5'; + when 6 => r(ptr) := '6'; + when 7 => r(ptr) := '7'; + when 8 => r(ptr) := '8'; + when 9 => r(ptr) := '9'; + when others => + assert false report lf & "TO_INT_STR, shouldn't happen" + severity failure; + return "$"; + end case; + int := int / 10; + ptr := ptr - 1; + end loop; + return format (r(ptr+1 to 32),decimal,rtn_len,justify,basespec); + end if; + end to_int_str; + + function to_int_str(x : std_logic_vector; + rtn_len : natural := 0; + justify : justify_side := right; + basespec : b_spec := yes) + return string is + begin + return to_int_str(to_nat(x),rtn_len,justify,basespec); + end to_int_str; + + + function to_time_str (x : time) + return string is + begin + return to_int_str(to_nat(x),basespec=>no) & " ns"; + end to_time_str; + + function fill (fill_char : character := '*'; + rtn_len : integer := 1) + return string is + variable r : string(1 to max(rtn_len,1)) := (others => fill_char); + variable len : integer; + begin + if rtn_len < 2 then -- always returns at least 1 fill char + len := 1; + else + len := rtn_len; + end if; + return r(1 to len); + end fill; + + function to_nat(x : std_logic_vector) return natural is + -- assumes x is an unsigned number, lsb on right, + -- more than 31 bits are truncated on left + variable t : std_logic_vector(1 to x'length) := x; + variable int : std_logic_vector(1 to 31) := (others => '0'); + variable r : natural := 0; + variable place : positive := 1; + begin + if x'length < 32 then + int(max(32-x'length,1) to 31) := t(1 to x'length); + else -- x'length >= 32 + int(1 to 31) := t(x'length-30 to x'length); + end if; + for i in int'reverse_range loop + case int(i) is + when '1' | 'H' => r := r + place; + when '0' | 'L' => null; + when others => + assert false + report lf & + "TO_NAT found illegal value: " & to_bin_str(int(i)) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + exit when i=1; + place := place * 2; + end loop; + return r; + end to_nat; + + function to_nat (x : std_logic) + return natural is + begin + case x is + when '0' => return 0 ; + when '1' => return 1 ; + when others => + assert false + report lf & + "TO_NAT found illegal value: " & to_bin_str(x) & lf & + "converting input to integer 0" + severity warning; + return 0; + end case; + end to_nat; + + function to_nat (x : time) + return natural is + begin + return x / 1 ns; + end to_nat; + + function h(x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length*4, result will be truncated on the left + -- if x is other than characters 0 to 9 or a,A to f,F or + -- x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length*4,rtn_len); + variable ptr : integer range -3 to size := size; + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr-3 to ptr) := "0000"; + when '1' => r(ptr-3 to ptr) := "0001"; + when '2' => r(ptr-3 to ptr) := "0010"; + when '3' => r(ptr-3 to ptr) := "0011"; + when '4' => r(ptr-3 to ptr) := "0100"; + when '5' => r(ptr-3 to ptr) := "0101"; + when '6' => r(ptr-3 to ptr) := "0110"; + when '7' => r(ptr-3 to ptr) := "0111"; + when '8' => r(ptr-3 to ptr) := "1000"; + when '9' => r(ptr-3 to ptr) := "1001"; + when 'a'|'A' => r(ptr-3 to ptr) := "1010"; + when 'b'|'B' => r(ptr-3 to ptr) := "1011"; + when 'c'|'C' => r(ptr-3 to ptr) := "1100"; + when 'd'|'D' => r(ptr-3 to ptr) := "1101"; + when 'e'|'E' => r(ptr-3 to ptr) := "1110"; + when 'f'|'F' => r(ptr-3 to ptr) := "1111"; + when 'U' => r(ptr-3 to ptr) := "UUUU"; + when 'X' => r(ptr-3 to ptr) := "XXXX"; + when 'Z' => r(ptr-3 to ptr) := "ZZZZ"; + when 'W' => r(ptr-3 to ptr) := "WWWW"; + when 'H' => r(ptr-3 to ptr) := "HHHH"; + when 'L' => r(ptr-3 to ptr) := "LLLL"; + when '-' => r(ptr-3 to ptr) := "----"; + when '_' => ptr := ptr + 4; + when others => + assert false + report lf & + "O conversion found illegal input character: " & + int(i) & lf & "converting character to '----'" + severity warning; + r(ptr-3 to ptr) := "----"; + end case; + ptr := ptr - 4; + end loop; + return r(size-rtn_len+1 to size); + end h; + + function d (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than binary length of x, result will be truncated on + -- the left + -- if x is other than characters 0 to 9, result will be 0 + begin + return to_slv(cnvt_base(x,10),rtn_len); + end d; + + function o (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length*3, result will be truncated on the left + -- if x is other than characters 0 to 7 or or x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length*3,rtn_len); + variable ptr : integer range -2 to size := size; + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr-2 to ptr) := "000"; + when '1' => r(ptr-2 to ptr) := "001"; + when '2' => r(ptr-2 to ptr) := "010"; + when '3' => r(ptr-2 to ptr) := "011"; + when '4' => r(ptr-2 to ptr) := "100"; + when '5' => r(ptr-2 to ptr) := "101"; + when '6' => r(ptr-2 to ptr) := "110"; + when '7' => r(ptr-2 to ptr) := "111"; + when 'U' => r(ptr-2 to ptr) := "UUU"; + when 'X' => r(ptr-2 to ptr) := "XXX"; + when 'Z' => r(ptr-2 to ptr) := "ZZZ"; + when 'W' => r(ptr-2 to ptr) := "WWW"; + when 'H' => r(ptr-2 to ptr) := "HHH"; + when 'L' => r(ptr-2 to ptr) := "LLL"; + when '-' => r(ptr-2 to ptr) := "---"; + when '_' => ptr := ptr + 3; + when others => + assert false + report lf & + "O conversion found illegal input character: " & + int(i) & lf & "converting character to '---'" + severity warning; + r(ptr-2 to ptr) := "---"; + end case; + ptr := ptr - 3; + end loop; + return r(size-rtn_len+1 to size); + end o; + + function b (x : string; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than x'length, result will be truncated on the left + -- if x is other than characters 0 to 1 or x,X,z,Z,u,U,-,w,W, + -- those result bits will be set to 0 + variable int : string(1 to x'length) := x; + variable size: positive := max(x'length,rtn_len); + variable ptr : integer range 0 to size+1 := size; -- csa + variable r : std_logic_vector(1 to size) := (others=>'0'); + begin + for i in int'reverse_range loop + case int(i) is + when '0' => r(ptr) := '0'; + when '1' => r(ptr) := '1'; + when 'U' => r(ptr) := 'U'; + when 'X' => r(ptr) := 'X'; + when 'Z' => r(ptr) := 'Z'; + when 'W' => r(ptr) := 'W'; + when 'H' => r(ptr) := 'H'; + when 'L' => r(ptr) := 'L'; + when '-' => r(ptr) := '-'; + when '_' => ptr := ptr + 1; + when others => + assert false + report lf & + "B conversion found illegal input character: " & + int(i) & lf & "converting character to '-'" + severity warning; + r(ptr) := '-'; + end case; + ptr := ptr - 1; + end loop; + return r(size-rtn_len+1 to size); + end b; + + function h (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 9 + -- a,A to f,F + -- blanks, underscore + begin + return cnvt_base(x,16); + end h; + + function d (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 9 + -- blanks, underscore + begin + return cnvt_base(x,10); + end d; + + function o (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 7 + -- blanks, underscore + begin + return cnvt_base(x,8); + end o; + + function b (x : string) + return natural is + -- only following characters are allowed, otherwise result will be 0 + -- 0 to 1 + -- blanks, underscore + begin + return cnvt_base(x,2); + end b; + + function to_slv(x : natural; + rtn_len : positive range 1 to 32 := 32) + return std_logic_vector is + -- if rtn_len is < than sizeof(x), result will be truncated on the left + variable int : natural := x; + variable ptr : positive := 32; + variable r : std_logic_vector(1 to 32) := (others=>'0'); + begin + while int > 0 loop + case int rem 2 is + when 0 => r(ptr) := '0'; + when 1 => r(ptr) := '1'; + when others => + assert false report lf & "TO_SLV, shouldn't happen" + severity failure; + return "0"; + end case; + int := int / 2; + ptr := ptr - 1; + end loop; + return r(33-rtn_len to 32); + end to_slv; + + function to_sl(x : natural) + return std_logic is + variable r : std_logic := '0'; + begin + case x is + when 0 => null; + when 1 => r := '1'; + when others => + assert false + report lf & + "TO_SL found illegal input character: " & + to_int_str(x) & lf & "converting character to '-'" + severity warning; + return '-'; + end case; + return r; + end to_sl; + + function to_time (x: natural) return time is + begin + return x * 1 ns; + end to_time; + +END conversions; diff --git a/lib/models/memory/flash/serial/S25fl032p/utilities/gen_utils.vhd b/lib/models/memory/flash/serial/S25fl032p/utilities/gen_utils.vhd new file mode 100644 index 0000000..65c0e77 --- /dev/null +++ b/lib/models/memory/flash/serial/S25fl032p/utilities/gen_utils.vhd @@ -0,0 +1,144 @@ +-------------------------------------------------------------------------------- +-- File name: gen_utils.vhd +-------------------------------------------------------------------------------- +-- Copyright (C) 1996, 1998, 2001 Free Model Foundry; http://eda.org/fmf/ +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License version 2 as +-- published by the Free Software Foundation. +-- +-- MODIFICATION HISTORY: +-- +-- version: | author: | mod date: | changes made: +-- V1.0 R. Steele 96 SEP 26 Initial release +-- V1.1 REV3 97 Feb 27 Added Xon and MsgOn generics +-- V1.2 R. Steele 97 APR 16 Changed wired-or to wired-and +-- V1.3 R. Steele 97 APR 16 Added diff. receiver table +-- V1.4 R. Munden 98 APR 13 Added GenParity and CheckParity +-- V1.5 R. Munden 01 NOV 24 Added UnitDelay01ZX +-- +-------------------------------------------------------------------------------- +LIBRARY IEEE; USE IEEE.std_Logic_1164.ALL; + USE IEEE.VITAL_primitives.ALL; + USE IEEE.VITAL_timing.ALL; + +PACKAGE gen_utils IS + + ---------------------------------------------------------------------------- + -- Result map for Wired-and output values (open collector) + ---------------------------------------------------------------------------- + CONSTANT STD_wired_and_rmap : VitalResultMapType := ('U','X','0','Z'); + + ---------------------------------------------------------------------------- + -- Table for computing a single signal from a differential receiver input + -- pair. + ---------------------------------------------------------------------------- + CONSTANT diff_rec_tab : VitalStateTableType := ( + + ------INPUTS--|-PREV-|-OUTPUT---- + -- A ANeg | Aint | Aint' -- + --------------|------|----------- + ( 'X', '-', '-', 'X'), -- A unknown + ( '-', 'X', '-', 'X'), -- A unknown + ( '1', '-', 'X', '1'), -- Recover from 'X' + ( '0', '-', 'X', '0'), -- Recover from 'X' + ( '/', '0', '0', '1'), -- valid diff. rising edge + ( '1', '\', '0', '1'), -- valid diff. rising edge + ( '\', '1', '1', '0'), -- valid diff. falling edge + ( '0', '/', '1', '0'), -- valid diff. falling edge + ( '-', '-', '-', 'S') -- default + ); -- end of VitalStateTableType definition + + + ---------------------------------------------------------------------------- + -- Default Constants + ---------------------------------------------------------------------------- + CONSTANT UnitDelay : VitalDelayType := 1 ns; + CONSTANT UnitDelay01 : VitalDelayType01 := (1 ns, 1 ns); + CONSTANT UnitDelay01Z : VitalDelayType01Z := (others => 1 ns); + CONSTANT UnitDelay01ZX : VitalDelayType01ZX := (others => 1 ns); + + CONSTANT DefaultInstancePath : STRING := "*"; + CONSTANT DefaultTimingChecks : BOOLEAN := FALSE; + CONSTANT DefaultTimingModel : STRING := "UNIT"; + CONSTANT DefaultXon : BOOLEAN := TRUE; + CONSTANT DefaultMsgOn : BOOLEAN := TRUE; + + -- Older VITAL generic being phased out + CONSTANT DefaultXGeneration : BOOLEAN := TRUE; + + ------------------------------------------------------------------- + -- Generate Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION GenParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic_vector; + + ------------------------------------------------------------------- + -- Check Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION CheckParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic; -- '0' - Parity Error + +END gen_utils; + +PACKAGE BODY gen_utils IS + + function XOR_REDUCE(ARG: STD_LOGIC_VECTOR) return UX01 is + -- pragma subpgm_id 403 + variable result: STD_LOGIC; + begin + result := '0'; + for i in ARG'range loop + result := result xor ARG(i); + end loop; + return result; + end; + ------------------------------------------------------------------- + -- Generate Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION GenParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic_vector + IS + VARIABLE I: NATURAL; + VARIABLE Result: std_logic_vector (Data'Length - 1 DOWNTO 0); + BEGIN + I := 0; + WHILE (I < SIZE) LOOP + Result(I+7 DOWNTO I) := Data(I+7 downto I); + Result(I+8) := XOR_REDUCE( Data(I+7 downto I) ) XOR ODDEVEN; + I := I + 9; + END LOOP; + RETURN Result; + END GenParity; + + ------------------------------------------------------------------- + -- Check Parity for each 8-bit in 9th bit + ------------------------------------------------------------------- + FUNCTION CheckParity + (Data : in std_logic_vector; -- Data + ODDEVEN : in std_logic; -- ODD (1) / EVEN(0) + SIZE : in POSITIVE) -- Bit Size + RETURN std_logic -- '0' - Parity Error + IS + VARIABLE I: NATURAL; + VARIABLE Result: std_logic; + BEGIN + I := 0; Result := '1'; + WHILE (I < SIZE) LOOP + Result := Result AND + NOT (XOR_REDUCE( Data(I+8 downto I) ) XOR ODDEVEN); + I := I + 9; + END LOOP; + RETURN Result; + END CheckParity; + +END gen_utils;