-------------------------------------------------------------------------------- -- File Name: m25p05a.vhd -------------------------------------------------------------------------------- -- Copyright (C) 2005 Free Model Foundry; http://www.FreeModelFoundation.com -- -- 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 M.Milanovic 05 Oct 28 Initial release -- -------------------------------------------------------------------------------- -- PART DESCRIPTION: -- -- Library: FLASH MEMORY -- Technology: CMOS -- Part: M25P05A -- -- Description: 512 KBit, Low Voltage, Serial Flash Memory -- With 50MHz SPI Bus Interface -------------------------------------------------------------------------------- LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; USE IEEE.VITAL_timing.ALL; USE IEEE.VITAL_primitives.ALL; USE STD.textio.ALL; LIBRARY FMF; USE FMF.gen_utils.ALL; USE FMF.conversions.ALL; -------------------------------------------------------------------------------- -- ENTITY DECLARATION -------------------------------------------------------------------------------- ENTITY m25p05a IS GENERIC ( -- tipd delays: interconnect path delays tipd_C : VitalDelayType01 := VitalZeroDelay01; tipd_D : VitalDelayType01 := VitalZeroDelay01; tipd_SNeg : VitalDelayType01 := VitalZeroDelay01; tipd_WNeg : VitalDelayType01 := VitalZeroDelay01; tipd_HOLDNeg : VitalDelayType01 := VitalZeroDelay01; -- tpd delays tpd_C_Q : VitalDelayType01Z := UnitDelay01Z; -- tCLQX(transi- -- tion to 'X'), -- tCLQV(trans. -- from 'X') tpd_HOLDNeg_Q : VitalDelayType01Z := UnitDelay01Z; -- tHHQX,tHLQZ tpd_SNeg_Q : VitalDelayType01Z := UnitDelay01Z; -- tSHQZ -- tsetup values tsetup_SNeg_C : VitalDelayType := UnitDelay; -- tSHCH tsetup_HOLDNeg_C : VitalDelayType := UnitDelay; -- tHLCH,tHHCH tsetup_D_C : VitalDelayType := UnitDelay; -- tDVCH tsetup_WNeg_SNeg : VitalDelayType := UnitDelay; -- tWHSL -- thold values thold_SNeg_C : VitalDelayType := UnitDelay; -- tCHSH thold_HOLDNeg_C : VitalDelayType := UnitDelay; -- tCHHH,tCHHL thold_D_C : VitalDelayType := UnitDelay; -- tCHDX thold_WNeg_SNeg : VitalDelayType := UnitDelay; -- tSHWL -- tpw values tpw_C : VitalDelayType := UnitDelay; -- tCL,tCH tpw_SNeg : VitalDelayType := UnitDelay; -- tSHSL -- tperiod values tperiod_C_READ : VitalDelayType := UnitDelay; -- 1/fR tperiod_C_OTHER : VitalDelayType := UnitDelay; -- 1/fC -- tdevice values: values for internal delays tdevice_tW : VitalDelayType := 15 ms; -- tW tdevice_tDP : VitalDelayType := 3 us; -- tDP tdevice_tRES1 : VitalDelayType := 3 us; -- tRES1 tdevice_tRES2 : VitalDelayType := 1.8 us; -- tRES2 tdevice_tPP : VitalDelayType := 5 ms; -- tPP tdevice_tSE : VitalDelayType := 3 sec; -- tSE tdevice_tBE : VitalDelayType := 6 sec; -- tBE tdevice_tVSL : VitalDelayType := 10 us; -- tVSL tdevice_tPUW : VitalDelayType := 10 ms; -- tPUW -- generic control parameters InstancePath : string := DefaultInstancePath; TimingChecksOn : boolean := DefaultTimingChecks; MsgOn : boolean := DefaultMsgOn; XOn : boolean := DefaultXon; -- memory file to be loaded mem_file_name : string := "none"; UserPreload : boolean := FALSE; -- For FMF SDF technology file usage TimingModel : string := DefaultTimingModel ); PORT ( C : IN std_ulogic := 'U'; D : IN std_ulogic := 'U'; SNeg : IN std_ulogic := 'U'; WNeg : IN std_ulogic := 'U'; HOLDNeg : IN std_ulogic := 'U'; Q : OUT std_ulogic := 'U' ); ATTRIBUTE VITAL_LEVEL0 OF m25p05a : ENTITY IS TRUE; END m25p05a; -------------------------------------------------------------------------------- -- ARCHITECTURE DECLARATION -------------------------------------------------------------------------------- ARCHITECTURE vhdl_behavioral OF m25p05a IS ATTRIBUTE VITAL_LEVEL0 OF vhdl_behavioral : ARCHITECTURE IS TRUE; CONSTANT PartID : string := "M25P05A"; CONSTANT SecSize : natural := 32767; CONSTANT SecNum : natural := 1; CONSTANT MaxData : natural := 255; CONSTANT MemSize : natural := (SecNum+1)*(SecSize+1)-1; CONSTANT PageSize : natural := 255; CONSTANT ManufacturerID : natural := 16#20#; CONSTANT DeviceID_1 : natural := 16#20#; CONSTANT DeviceID_2 : natural := 16#10#; CONSTANT El_signature : natural := 16#05#; CONSTANT Program_base : real := 2.0/7; -- implementation of linear Page CONSTANT Program_coeff : real := 5.0/7; -- Program time when less than -- 256 bytes are programmed -- ipd SIGNAL C_ipd : std_ulogic := 'U'; SIGNAL D_ipd : std_ulogic := 'U'; SIGNAL SNeg_ipd : std_ulogic := 'U'; SIGNAL WNeg_ipd : std_ulogic := 'U'; SIGNAL HOLDNeg_ipd : std_ulogic := 'U'; -- nwv SIGNAL C_nwv : std_ulogic := 'U'; SIGNAL D_nwv : std_ulogic := 'U'; SIGNAL SNeg_nwv : std_ulogic := 'U'; SIGNAL WNeg_nwv : std_ulogic := 'U'; SIGNAL HOLDNeg_nwv : std_ulogic := 'U'; --- internal delays SIGNAL tW_in : std_ulogic := '0'; SIGNAL tW_out : std_ulogic := '0'; SIGNAL tDP_in : std_ulogic := '0'; SIGNAL tDP_out : std_ulogic := '0'; SIGNAL tRES1_in : std_ulogic := '0'; SIGNAL tRES1_out : std_ulogic := '0'; SIGNAL tRES2_in : std_ulogic := '0'; SIGNAL tRES2_out : std_ulogic := '0'; SIGNAL tPP_in : std_ulogic := '0'; SIGNAL tPP_out : std_ulogic := '0'; SIGNAL tSE_in : std_ulogic := '0'; SIGNAL tSE_out : std_ulogic := '0'; SIGNAL tBE_in : std_ulogic := '0'; SIGNAL tBE_out : std_ulogic := '0'; SIGNAL tVSL_in : std_ulogic := '0'; SIGNAL tVSL_out : std_ulogic := '0'; SIGNAL tPUW_in : std_ulogic := '0'; SIGNAL tPUW_out : std_ulogic := '0'; BEGIN ---------------------------------------------------------------------------- -- Internal Delays ---------------------------------------------------------------------------- -- Artificial VITAL primitives to incorporate internal delays TW : VitalBuf(tW_out, tW_in, (tdevice_tW, UnitDelay)); TDP : VitalBuf(tDP_out, tDP_in, (tdevice_tDP, UnitDelay)); TRES1 : VitalBuf(tRES1_out, tRES1_in, (tdevice_tRES1, UnitDelay)); TRES2 : VitalBuf(tRES2_out, tRES2_in, (tdevice_tRES2, UnitDelay)); TPP : VitalBuf(tPP_out, tPP_in, (tdevice_tPP, UnitDelay)); TSE : VitalBuf(tSE_out, tSE_in, (tdevice_tSE, UnitDelay)); TBE : VitalBuf(tBE_out, tBE_in, (tdevice_tBE, UnitDelay)); TVSL : VitalBuf(tVSL_out, tVSL_in, (tdevice_tVSL, UnitDelay)); TPUW : VitalBuf(tPUW_out, tPUW_in, (tdevice_tPUW, UnitDelay)); ---------------------------------------------------------------------------- -- Wire Delays ---------------------------------------------------------------------------- WireDelay : BLOCK BEGIN w_01 : VitalWireDelay (C_ipd, C, tipd_C); w_02 : VitalWireDelay (D_ipd, D, tipd_D); w_03 : VitalWireDelay (SNeg_ipd, SNeg, tipd_SNeg); w_04 : VitalWireDelay (WNeg_ipd, WNeg, tipd_WNeg); w_05 : VitalWireDelay (HOLDNeg_ipd, HOLDNeg, tipd_HOLDNeg); END BLOCK; -- sig_nwv <= To_UX01(sig_ipd); C_nwv <= To_UX01(C_ipd); D_nwv <= To_UX01(D_ipd); SNeg_nwv <= To_UX01(SNeg_ipd); WNeg_nwv <= To_UX01(WNeg_ipd); HOLDNeg_nwv <= To_UX01(HOLDNeg_ipd); ---------------------------------------------------------------------------- -- Main Behavior Block ---------------------------------------------------------------------------- Behavior: BLOCK PORT ( C : IN std_ulogic := 'U'; D : IN std_ulogic := 'U'; SNeg : IN std_ulogic := 'U'; WNeg : IN std_ulogic := 'U'; HOLDNeg : IN std_ulogic := 'U'; Q : OUT std_ulogic := 'U' ); PORT MAP ( C => C_nwv, D => D_nwv, SNeg => SNeg_nwv, WNeg => WNeg_nwv, HOLDNeg => HOLDNeg_nwv, Q => Q ); --zero delay signals SIGNAL Q_zd : std_logic := 'Z'; -- powerup SIGNAL PoweredUp1 : boolean := FALSE; SIGNAL PoweredUp2 : boolean := FALSE; --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; SHARED VARIABLE Mem : MemArray := (OTHERS => (OTHERS => MaxData)); SIGNAL Hold_cond : boolean := FALSE; SIGNAL Code_toggle : boolean := FALSE; -- signals 8-bit code change SIGNAL Read_period : boolean := FALSE; -- period check during READ ins. SIGNAL highZ_cond : boolean := FALSE; -- output goes high-Z after 3 ID -- bytes are read or maximum -- address reached SIGNAL Byte_cnt : natural RANGE 0 TO PageSize+1; SIGNAL Prog_in : std_logic := '0'; -- Programming start SIGNAL Prog_out : std_logic := '0'; -- Programming end BEGIN ---------------------------------------------------------------------------- -- Power Up times tVSL, tPUW ---------------------------------------------------------------------------- PoweredUp1 <= TRUE AFTER tdevice_tVSL; PoweredUp2 <= TRUE AFTER tdevice_tPUW; ---------------------------------------------------------------------------- -- Main Behavior Process ---------------------------------------------------------------------------- VITALBehaviour: PROCESS(C, D, SNeg, WNeg, HOLDNeg) -- Timing Check Variables VARIABLE Tviol_SNeg_C : X01 := '0'; VARIABLE TD_SNeg_C : VitalTimingDataType; VARIABLE Tviol_HOLDNeg_C : X01 := '0'; VARIABLE TD_HOLDNeg_C : VitalTimingDataType; VARIABLE Tviol_D_C : X01 := '0'; VARIABLE TD_D_C : VitalTimingDataType; VARIABLE Tviol_WNeg_SNeg0 : X01 := '0'; VARIABLE TD_WNeg_SNeg0 : VitalTimingDataType; VARIABLE Tviol_WNeg_SNeg1 : X01 := '0'; VARIABLE TD_WNeg_SNeg1 : VitalTimingDataType; VARIABLE Pviol_C0 : X01 := '0'; VARIABLE PD_C0 : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Pviol_C1 : X01 := '0'; VARIABLE PD_C1 : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Pviol_SNeg : X01 := '0'; VARIABLE PD_SNeg : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Violation : X01 := '0'; BEGIN ---------------------------------------------------------------------------- -- Timing Check Section ---------------------------------------------------------------------------- IF (TimingChecksOn) THEN -- Setup/Hold Check between SNeg and C VitalSetupHoldCheck ( TestSignal => SNeg, TestSignalName => "SNeg", RefSignal => C, RefSignalName => "C", SetupHigh => tsetup_SNeg_C, SetupLow => tsetup_SNeg_C, HoldHigh => thold_SNeg_C, HoldLow => thold_SNeg_C, CheckEnabled => TRUE, RefTransition => '/', HeaderMsg => InstancePath & PartID, TimingData => TD_SNeg_C, Violation => Tviol_SNeg_C ); -- Setup/Hold Check between HOLDNeg and C VitalSetupHoldCheck ( TestSignal => HOLDNeg, TestSignalName => "HOLDNeg", RefSignal => C, RefSignalName => "C", SetupHigh => tsetup_HOLDNeg_C, SetupLow => tsetup_HOLDNeg_C, HoldHigh => thold_HOLDNeg_C, HoldLow => thold_HOLDNeg_C, CheckEnabled => TRUE, RefTransition => '/', HeaderMsg => InstancePath & PartID, TimingData => TD_HOLDNeg_C, Violation => Tviol_HOLDNeg_C ); -- Setup/Hold Check between D and C VitalSetupHoldCheck ( TestSignal => D, TestSignalName => "D", RefSignal => C, RefSignalName => "C", SetupHigh => tsetup_D_C, SetupLow => tsetup_D_C, HoldHigh => thold_D_C, HoldLow => thold_D_C, CheckEnabled => TRUE, RefTransition => '/', HeaderMsg => InstancePath & PartID, TimingData => TD_D_C, Violation => Tviol_D_C ); -- Setup Check between WNeg and SNeg VitalSetupHoldCheck ( TestSignal => WNeg, TestSignalName => "WNeg", RefSignal => SNeg, RefSignalName => "SNeg", SetupHigh => tsetup_WNeg_SNeg, CheckEnabled => TRUE, RefTransition => '\', HeaderMsg => InstancePath & PartID, TimingData => TD_WNeg_SNeg0, Violation => Tviol_WNeg_SNeg0 ); -- Hold Check between WNeg and SNeg VitalSetupHoldCheck ( TestSignal => WNeg, TestSignalName => "WNeg", RefSignal => SNeg, RefSignalName => "SNeg", HoldHigh => thold_WNeg_SNeg, CheckEnabled => TRUE, RefTransition => '/', HeaderMsg => InstancePath & PartID, TimingData => TD_WNeg_SNeg1, Violation => Tviol_WNeg_SNeg1 ); -- PulseWidth and Period Check for C (READ) VitalPeriodPulseCheck ( TestSignal => C, TestSignalName => "C", Period => tperiod_C_READ, PulseWidthHigh => tpw_C, PulseWidthLow => tpw_C, CheckEnabled => Read_period, HeaderMsg => InstancePath & PartID, PeriodData => PD_C0, Violation => Pviol_C0 ); -- PulseWidth and Period Check for C (other) VitalPeriodPulseCheck ( TestSignal => C, TestSignalName => "C", Period => tperiod_C_OTHER, PulseWidthHigh => tpw_C, PulseWidthLow => tpw_C, CheckEnabled => NOT Read_period, HeaderMsg => InstancePath & PartID, PeriodData => PD_C1, Violation => Pviol_C1 ); -- PulseWidth Check for SNeg VitalPeriodPulseCheck ( TestSignal => SNeg, TestSignalName => "SNeg", PulseWidthHigh => tpw_SNeg, CheckEnabled => TRUE, HeaderMsg => InstancePath & PartID, PeriodData => PD_SNeg, Violation => Pviol_SNeg ); Violation := Tviol_SNeg_C OR Tviol_HOLDNeg_C OR Tviol_D_C OR Tviol_WNeg_SNeg0 OR Tviol_WNeg_SNeg1 OR Pviol_C0 OR Pviol_C1 OR Pviol_SNeg; ASSERT Violation = '0' REPORT InstancePath & partID & ": simulation may be" & " inaccurate due to timing violations" SEVERITY warning; END IF; END PROCESS VITALBehaviour; ---------------------------------------------------------------------------- -- Functionality process ---------------------------------------------------------------------------- Functionality: PROCESS(C, Code_toggle, SNeg, tW_out, tSE_out, tBE_out, Prog_out, tDP_out, tRES1_out, tRES2_out, HOLDNeg) VARIABLE Comm_code : natural RANGE 0 TO MaxData; TYPE Last_comm_type IS (no_command, seen_06, seen_04, seen_05, seen_01, seen_03, seen_0B, seen_9F, seen_D8, seen_C7, seen_02, seen_B9, seen_AB, addr_read_1, addr_read_2, addr_read_3, addr_fast_read_1, addr_fast_read_2, addr_fast_read_3, dummy_fast_read, addr_se_1, addr_se_2, addr_se_3, addr_pp_1, addr_pp_2, addr_pp_3, dummy_res_1, dummy_res_2, dummy_res_3, byte_wrsr, byte_pp, wrsr_execute, se_execute, be_execute, pp_execute, dp_execute, wrsr_seen_05, se_seen_05, be_seen_05, pp_seen_05, dp_start, dp_seen_AB, dp_dummy_1, dp_dummy_2, dp_dummy_3, dp_release); VARIABLE Last_comm : Last_comm_type := no_command; VARIABLE Comm_reg : std_logic_vector(7 DOWNTO 0); -- collects bits for -- Comm_code VARIABLE SRWD : natural RANGE 0 TO 1 := 0; VARIABLE BP1 : natural RANGE 0 TO 1 := 0; VARIABLE BP0 : natural RANGE 0 TO 1 := 0; VARIABLE WEL : natural RANGE 0 TO 1 := 0; VARIABLE WIP : natural RANGE 0 TO 1 := 0; VARIABLE Address : std_logic_vector(23 DOWNTO 0); TYPE Prog_reg_type IS ARRAY (0 TO PageSize) OF integer RANGE -1 TO MaxData; VARIABLE Program_reg : Prog_reg_type; -- collects bytes for PP VARIABLE Byte_order : natural RANGE 0 TO PageSize := 1; VARIABLE Whole_page : boolean := FALSE; -- +256 bytes in PP VARIABLE Byte_sr : std_logic_vector(7 DOWNTO 0); -- WRSR byte VARIABLE Bit_pos_in : natural RANGE 0 TO 7 := 0; VARIABLE Bit_pos_out : natural RANGE 0 TO 24 := 0; VARIABLE Hold_irr_flag : boolean := FALSE; -- SNeg went high during -- hold condition VARIABLE Sector : natural RANGE 0 TO SecNum; VARIABLE Prog_addr : natural RANGE 0 TO MemSize; -- given by PP VARIABLE Prog_count : natural RANGE 0 TO PageSize; -- programmed bytes VARIABLE Addr_temp : natural RANGE 0 TO SecSize; -- within sector VARIABLE Old_byte : std_logic_vector(7 DOWNTO 0); VARIABLE New_byte : std_logic_vector(7 DOWNTO 0); VARIABLE Addr : natural RANGE 0 TO MemSize; -- read address VARIABLE Read_sect : natural RANGE 0 TO SecNum; VARIABLE Read_addr : natural RANGE 0 TO SecSize; -- within sector VARIABLE Read_data : std_logic_vector(7 DOWNTO 0); -- output byte VARIABLE ID_byte : std_logic_vector(7 DOWNTO 0); -- RDID, RES output VARIABLE Inst_start : boolean := FALSE; -- start of instruction VARIABLE Max_addr : boolean := FALSE; -- last memory location read VARIABLE El_sign_read : boolean := FALSE; -- electronic signature read FUNCTION Prot_sect (Sect : natural RANGE 0 TO SecNum; BP_sum : natural RANGE 0 TO 3) RETURN boolean IS VARIABLE Prot : boolean; BEGIN IF BP_sum = 0 OR BP_sum = 1 OR BP_sum = 2 THEN Prot := FALSE; ELSE Prot := TRUE; END IF; RETURN Prot; END Prot_sect; BEGIN IF falling_edge(SNeg) AND PoweredUp1 THEN Inst_start := TRUE; END IF; IF rising_edge(C) AND SNeg = '0' AND NOT Hold_cond AND Inst_start THEN -- collecting Comm_code bits Comm_reg(7-Bit_pos_in) := D; IF Bit_pos_in = 7 THEN Bit_pos_in := 0; Comm_code := to_nat(Comm_reg(7 DOWNTO 0)); Code_toggle <= NOT Code_toggle; ELSE Bit_pos_in := Bit_pos_in + 1; END IF; END IF; IF rising_edge(C) AND SNeg = '0' AND (Last_comm = byte_wrsr OR Last_comm = addr_se_3 OR Last_comm = seen_C7 OR Last_comm = seen_06 OR Last_comm = seen_04 OR Last_comm = seen_B9) THEN -- CS# not deasserted in time for WRSR, SE, BE, WREN, WRDI or DP Last_comm := no_command; Inst_start := FALSE; END IF; IF Code_toggle'EVENT THEN -- state transition CASE Last_comm IS WHEN no_command => IF Comm_code = 16#06# AND PoweredUp2 THEN Last_comm := seen_06; ELSIF Comm_code = 16#04# THEN Last_comm := seen_04; ELSIF Comm_code = 16#05# THEN Last_comm := seen_05; ELSIF Comm_code = 16#01# AND WEL = 1 AND (SRWD = 0 OR WNeg = '1') AND PoweredUp2 THEN Last_comm := seen_01; ELSIF Comm_code = 16#03# AND WIP = 0 THEN Last_comm := seen_03; ELSIF Comm_code = 16#0B# AND WIP = 0 THEN Last_comm := seen_0B; ELSIF Comm_code = 16#9F# AND WIP = 0 THEN Last_comm := seen_9F; ELSIF Comm_code = 16#D8# AND WEL = 1 AND PoweredUp2 THEN Last_comm := seen_D8; ELSIF Comm_code = 16#C7# AND WEL = 1 AND BP1 = 0 AND BP0 = 0 AND PoweredUp2 THEN Last_comm := seen_C7; ELSIF Comm_code = 16#02# AND WEL = 1 AND PoweredUp2 THEN Last_comm := seen_02; ELSIF Comm_code = 16#B9# AND WIP = 0 THEN Last_comm := seen_B9; ELSIF Comm_code = 16#AB# AND WIP = 0 THEN Last_comm := seen_AB; ELSE Inst_start := FALSE; END IF; WHEN seen_01 => Last_comm := byte_wrsr; Byte_sr := to_slv(Comm_code, 8); WHEN seen_03 => Last_comm := addr_read_1; Address(23 DOWNTO 16) := to_slv(Comm_code, 8); WHEN addr_read_1 => Last_comm := addr_read_2; Address(15 DOWNTO 8) := to_slv(Comm_code, 8); WHEN addr_read_2 => Address(7 DOWNTO 0) := to_slv(Comm_code, 8); IF to_nat(Address) <= MemSize THEN Last_comm := addr_read_3; ELSE Last_comm := no_command; Inst_start := FALSE; REPORT "Address is out of range" SEVERITY warning; END IF; WHEN seen_0B => Last_comm := addr_fast_read_1; Address(23 DOWNTO 16) := to_slv(Comm_code, 8); WHEN addr_fast_read_1 => Last_comm := addr_fast_read_2; Address(15 DOWNTO 8) := to_slv(Comm_code, 8); WHEN addr_fast_read_2 => Last_comm := addr_fast_read_3; Address(7 DOWNTO 0) := to_slv(Comm_code, 8); WHEN addr_fast_read_3 => IF to_nat(Address) <= MemSize THEN Last_comm := dummy_fast_read; ELSE Last_comm := no_command; Inst_start := FALSE; REPORT "Address is out of range" SEVERITY warning; END IF; WHEN seen_D8 => Last_comm := addr_se_1; Address(23 DOWNTO 16) := to_slv(Comm_code, 8); WHEN addr_se_1 => Last_comm := addr_se_2; Address(15 DOWNTO 8) := to_slv(Comm_code, 8); WHEN addr_se_2 => Last_comm := addr_se_3; Address(7 DOWNTO 0) := to_slv(Comm_code, 8); WHEN seen_02 => Last_comm := addr_pp_1; Address(23 DOWNTO 16) := to_slv(Comm_code, 8); WHEN addr_pp_1 => Last_comm := addr_pp_2; Address(15 DOWNTO 8) := to_slv(Comm_code, 8); WHEN addr_pp_2 => Last_comm := addr_pp_3; Address(7 DOWNTO 0) := to_slv(Comm_code, 8); WHEN addr_pp_3 => Last_comm := byte_pp; Program_reg(0) := Comm_code; WHEN byte_pp => IF Whole_page THEN FOR I IN 0 TO PageSize-1 LOOP Program_reg(I) := Program_reg(I+1); END LOOP; END IF; Program_reg(Byte_order) := Comm_code; IF Byte_order = PageSize THEN Whole_page := TRUE; ELSE Byte_order := Byte_order + 1; END IF; WHEN seen_AB => Last_comm := dummy_res_1; WHEN dummy_res_1 => Last_comm := dummy_res_2; WHEN dummy_res_2 => Last_comm := dummy_res_3; WHEN wrsr_execute => IF Comm_code = 16#05# THEN Last_comm := wrsr_seen_05; ELSE Inst_start := FALSE; END IF; WHEN se_execute => IF Comm_code = 16#05# THEN Last_comm := se_seen_05; ELSE Inst_start := FALSE; END IF; WHEN be_execute => IF Comm_code = 16#05# THEN Last_comm := be_seen_05; ELSE Inst_start := FALSE; END IF; WHEN pp_execute => IF Comm_code = 16#05# THEN Last_comm := pp_seen_05; ELSE Inst_start := FALSE; END IF; WHEN dp_start => IF Comm_code = 16#AB# THEN Last_comm := dp_seen_AB; ELSE Inst_start := FALSE; END IF; WHEN dp_seen_AB => Last_comm := dp_dummy_1; WHEN dp_dummy_1 => Last_comm := dp_dummy_2; WHEN dp_dummy_2 => Last_comm := dp_dummy_3; WHEN OTHERS => END CASE; END IF; IF rising_edge(SNeg) AND NOT Hold_cond THEN -- end of instruction CASE Last_comm IS WHEN byte_wrsr => Last_comm := wrsr_execute; SRWD := to_nat(Byte_sr(7)); BP1 := to_nat(Byte_sr(3)); BP0 := to_nat(Byte_sr(2)); WIP := 1; tW_in <= '1'; WHEN addr_se_3 => IF to_nat(Address) <= MemSize THEN Sector := to_nat(Address) / (SecSize + 1); IF NOT Prot_sect(Sector, 2*BP1+BP0) THEN Last_comm := se_execute; Mem(Sector) := (OTHERS => MaxData); WIP := 1; tSE_in <= '1'; ELSE Last_comm := no_command; END IF; ELSE Last_comm := no_command; REPORT "Address is out of range" SEVERITY warning; END IF; WHEN seen_C7 => Last_comm := be_execute; Mem := (OTHERS => (OTHERS => MaxData)); WIP := 1; tBE_in <= '1'; WHEN byte_pp => IF Bit_pos_in = 0 THEN -- CS# deasserted in time for PP instruction IF to_nat(Address) <= MemSize THEN Prog_addr := to_nat(Address); Sector := Prog_addr / (SecSize + 1); Addr_temp := Prog_addr MOD (SecSize+1); IF Whole_page THEN Prog_count := PageSize; ELSE Prog_count := Byte_order - 1; END IF; Byte_cnt <= Prog_count + 1; IF NOT Prot_sect(Sector, 2*BP1+BP0) THEN Last_comm := pp_execute; FOR I IN 0 TO Prog_count LOOP Old_byte := to_slv(Mem(Sector)(Addr_temp), 8); New_byte := to_slv(Program_reg(I), 8); FOR J IN 0 TO 7 LOOP IF Old_byte(J) = '0' THEN New_byte(J) := '0'; END IF; END LOOP; Mem(Sector)(Addr_temp) := to_nat(New_byte); IF Addr_temp MOD (PageSize+1) = PageSize THEN Addr_temp := Addr_temp - PageSize; ELSE Addr_temp := Addr_temp + 1; END IF; END LOOP; WIP := 1; Prog_in <= '1'; ELSE Last_comm := no_command; END IF; ELSE Last_comm := no_command; REPORT "Address is out of range" SEVERITY warning; END IF; ELSE Last_comm := no_command; END IF; Byte_order := 1; Whole_page := FALSE; WHEN seen_06 => Last_comm := no_command; WEL := 1; WHEN seen_04 => Last_comm := no_command; WEL := 0; WHEN seen_B9 | dp_execute => Last_comm := dp_execute; tDP_in <= '1'; WHEN wrsr_seen_05 | wrsr_execute => Last_comm := wrsr_execute; WHEN se_seen_05 | se_execute => Last_comm := se_execute; WHEN be_seen_05 | be_execute => Last_comm := be_execute; WHEN pp_seen_05 | pp_execute => Last_comm := pp_execute; WHEN dp_seen_AB | dp_dummy_1 | dp_dummy_2 | dp_dummy_3 => Last_comm := dp_release; IF NOT El_sign_read THEN tRES1_in <= '1'; ELSE tRES2_in <= '1'; END IF; WHEN dp_start => WHEN OTHERS => Last_comm := no_command; END CASE; Read_period <= FALSE; highZ_cond <= FALSE; Max_addr := FALSE; El_sign_read := FALSE; Bit_pos_in := 0; Bit_pos_out := 0; Q_zd <= 'Z'; END IF; IF rising_edge(tW_out) AND Last_comm = wrsr_execute THEN -- end of writing status register WEL := 0; WIP := 0; Last_comm := no_command; tW_in <= '0'; END IF; IF rising_edge(tSE_out) AND Last_comm = se_execute THEN -- end of sector erasure WEL := 0; WIP := 0; Last_comm := no_command; tSE_in <= '0'; END IF; IF rising_edge(tBE_out) AND Last_comm = be_execute THEN -- end of bulk erasure WEL := 0; WIP := 0; Last_comm := no_command; tBE_in <= '0'; END IF; IF rising_edge(Prog_out) AND Last_comm = pp_execute THEN -- end of programming WEL := 0; WIP := 0; Last_comm := no_command; Prog_in <= '0'; END IF; IF rising_edge(tDP_out) AND Last_comm = dp_execute THEN -- start of deep power down mode Last_comm := dp_start; tDP_in <= '0'; END IF; IF falling_edge(SNeg) AND Last_comm = dp_release THEN -- CS# not high long enough to exit deep power down mode Last_comm := dp_start; tRES1_in <= '0'; tRES2_in <= '0'; END IF; IF ((tRES1_out'EVENT AND tRES1_out = '1') OR (tRES2_out'EVENT AND tRES2_out = '1')) AND Last_comm = dp_release THEN -- deep power down mode exit Last_comm := no_command; tRES1_in <= '0'; tRES2_in <= '0'; END IF; IF ((falling_edge(HOLDNeg) AND C = '0') OR (falling_edge(C) AND HOLDNeg = '0')) AND SNeg = '0' THEN -- start of hold condition Hold_cond <= TRUE; Q_zd <= 'Z'; END IF; IF rising_edge(SNeg) AND Hold_cond THEN -- irregular device internal logic reset Last_comm := no_command; Hold_irr_flag := TRUE; Read_period <= FALSE; highZ_cond <= FALSE; Max_addr := FALSE; El_sign_read := FALSE; Bit_pos_in := 0; Bit_pos_out := 0; END IF; IF (((rising_edge(HOLDNeg) AND C = '0') OR (falling_edge(C) AND HOLDNeg = '1')) AND NOT Hold_irr_flag) OR (falling_edge(SNeg) AND HOLDNeg = '1' AND Hold_irr_flag) THEN -- hold condition exit Hold_cond <= FALSE; Hold_irr_flag := FALSE; END IF; IF falling_edge(C) AND SNeg = '0' AND (NOT Hold_cond OR (HOLDNeg = '1' AND NOT Hold_irr_flag)) AND HOLDNeg /= '0' THEN -- output generation CASE Last_comm IS WHEN seen_05 | wrsr_seen_05 | se_seen_05 | be_seen_05 | pp_seen_05 => CASE Bit_pos_out IS WHEN 0 => Q_zd <= 'X', to_sl(SRWD) AFTER 1 ns; WHEN 1 | 2 | 3 => Q_zd <= 'X', '0' AFTER 1 ns; WHEN 4 => Q_zd <= 'X', to_sl(BP1) AFTER 1 ns; WHEN 5 => Q_zd <= 'X', to_sl(BP0) AFTER 1 ns; WHEN 6 => Q_zd <= 'X', to_sl(WEL) AFTER 1 ns; WHEN 7 => Q_zd <= 'X', to_sl(WIP) AFTER 1 ns; WHEN OTHERS => END CASE; IF Bit_pos_out = 7 THEN Bit_pos_out := 0; ELSE Bit_pos_out := Bit_pos_out + 1; END IF; WHEN addr_read_3 | dummy_fast_read => IF Max_addr THEN highZ_cond <= TRUE; Q_zd <= 'X', 'Z' AFTER 1 ns; ELSE IF Last_comm = addr_read_3 THEN Read_period <= TRUE; END IF; Addr := to_nat(Address); Read_sect := Addr / (SecSize+1); Read_addr := Addr MOD (SecSize+1); Read_data := to_slv(Mem(Read_sect)(Read_addr), 8); Q_zd <= 'X', Read_data(7-Bit_pos_out) AFTER 1 ns; IF Bit_pos_out = 7 THEN Bit_pos_out := 0; IF Addr = MemSize THEN Max_addr := TRUE; ELSE Address := to_slv(Addr+1, 24); END IF; ELSE Bit_pos_out := Bit_pos_out + 1; END IF; END IF; WHEN seen_9F => IF Bit_pos_out = 24 THEN highZ_cond <= TRUE; Q_zd <= 'X', 'Z' AFTER 1 ns; ELSE IF Bit_pos_out <= 7 THEN ID_byte := to_slv(ManufacturerID, 8); Q_zd <= 'X', ID_byte(7-Bit_pos_out) AFTER 1 ns; ELSIF Bit_pos_out <= 15 THEN ID_byte := to_slv(DeviceID_1, 8); Q_zd <= 'X', ID_byte(15-Bit_pos_out) AFTER 1 ns; ELSE ID_byte := to_slv(DeviceID_2, 8); Q_zd <= 'X', ID_byte(23-Bit_pos_out) AFTER 1 ns; END IF; Bit_pos_out := Bit_pos_out + 1; END IF; WHEN dummy_res_3 | dp_dummy_3 => ID_byte := to_slv(El_signature, 8); Q_zd <= 'X', ID_byte(7-Bit_pos_out) AFTER 1 ns; IF Bit_pos_out = 7 THEN El_sign_read := TRUE; Bit_pos_out := 0; ELSE Bit_pos_out := Bit_pos_out + 1; END IF; WHEN OTHERS => END CASE; END IF; END PROCESS Functionality; Page_program: PROCESS(Prog_in) BEGIN IF rising_edge(Prog_in) THEN IF Byte_cnt <= PageSize THEN Prog_out <= '1' AFTER (Program_base + Program_coeff * (real(Byte_cnt)/256.0)) * tdevice_tPP; ELSE Prog_out <= '1' AFTER tdevice_tPP; END IF; END IF; IF falling_edge(Prog_in) THEN Prog_out <= '0'; END IF; END PROCESS Page_program; default: PROCESS -- Text file input variables FILE mem_file : text IS mem_file_name; VARIABLE S_ind : natural RANGE 0 TO SecNum := 0; VARIABLE ind : natural := 0; VARIABLE index : natural RANGE 0 TO SecSize := 0; VARIABLE buf : line; BEGIN -- Preload Control ------------------------------------------------------------------------ -- File Read Section ------------------------------------------------------------------------ ------------------------------------------------------------------------ ---- m25p05a memory preload file format -------------------------------- ------------------------------------------------------------------------ -- / - comment -- @aaaa - stands for address within memory -- dd -
is byte to be written at Mem(aaaa++) -- (aaaa is incremented at every load) -- only first 1-5 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! ------------------------------------------------------------------------ IF UserPreload THEN IF mem_file_name /= "none" THEN ind := 0; S_ind := 0; Mem := (OTHERS => (OTHERS => MaxData)); WHILE NOT ENDFILE (mem_file) LOOP READLINE (mem_file, buf); IF buf(1) = '/' THEN NEXT; ELSIF buf(1) = '@' THEN ind := h(buf(2 TO 5)); --address ELSE IF ind=0 THEN S_ind := 0; index := 0; ELSIF ind < SecSize+1 THEN S_ind := 0; index := ind; ELSE S_ind := natural(ind / (SecSize+1)); index := ind - S_ind*(SecSize+1); END IF; Mem(S_ind)(index) := h(buf(1 TO 2)); ind := ind + 1; END IF; END LOOP; END IF; END IF; WAIT; END PROCESS default; ---------------------------------------------------------------------------- -- Path Delay Section ---------------------------------------------------------------------------- PROCESS(Q_zd) VARIABLE Q_GlitchData : VitalGlitchDataType; BEGIN VitalPathDelay01Z( OutSignal => Q, OutSignalName => "Q", OutTemp => Q_zd, Mode => VitalTransport, GlitchData => Q_GlitchData, Paths => ( 0 => (InputChangeTime => C'LAST_EVENT, PathDelay => tpd_C_Q, PathCondition => NOT Hold_cond AND NOT highZ_cond), -- start of hold condition on C falling edge: 1 => (InputChangeTime => C'LAST_EVENT, PathDelay => tpd_HOLDNeg_Q, PathCondition => Hold_cond), -- transition to 'Z' when 3 ID bytes are read or -- maximum address reached: 2 => (InputChangeTime => C'LAST_EVENT, PathDelay => tpd_SNeg_Q, PathCondition => NOT Hold_cond AND highZ_cond), 3 => (InputChangeTime => HOLDNeg'LAST_EVENT, PathDelay => tpd_HOLDNeg_Q, PathCondition => TRUE), 4 => (InputChangeTime => SNeg'LAST_EVENT, PathDelay => tpd_SNeg_Q, PathCondition => TRUE) ) ); END PROCESS; END BLOCK behavior; END vhdl_behavioral;