-- VHDL Model for an Everspin  1M x 16 MRAM
-- Device Part Number: MR4A16B
-- Device Data Sheet: http://www.everspin.com/PDF/EST_MR4A16B_prod.pdf

-- Model Revision: 2.1  2025-02-14
-- Fix bug in Tavwh measurement

-- Model Revision: 2.0  2011-01-15

-- Model Revision: 3.0  2025-06-30

---------------------------------------------------------------------
-- These VHDL models are provided "as is" without warranty of
-- any kind, included but not limited to, implied warranty of
-- merchant ability and fitness for a particular purpose.
---------------------------------------------------------------------

LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
LIBRARY STD;
USE STD.TEXTIO.ALL;
LIBRARY WORK;
USE WORK.PACKAGE_UTILITY.ALL;

--===================================================================
-- Entity for MR4A16B
--===================================================================

 Entity MR4A16B IS
	   GENERIC (Tavav:   TIME    :=   35 ns;	-- Read Cycle Time
	            Tavqv:   TIME    :=   35 ns;	-- Address to Data Valid
	            Taxqx:   TIME    :=   3 ns; 	-- Output Hold from Address Change
	            Telqv:   TIME    :=   35 ns;	-- Chip Enable to Data Valid
	            Tglqv:   TIME    :=   15 ns;	-- OE to Data Valid
	            Tghqz:   TIME    :=   10 ns;	-- OE to High Z
	            Tbhqz:   TIME    :=   10 ns;	-- Byte Enable to High Z
	            Tehqz:   TIME    :=   15 ns;	-- Chip Enable to High Z
	            Teleh:   TIME    :=   0 ns; 	-- Chip Enable to end of Write
	            Tavwh:   TIME    :=   20 ns;	-- Address Valid to End of Write
	            Twhax:   TIME    :=   12 ns;	-- Write Recovery Time
	            Tavwl:   TIME    :=   0 ns;		-- Address Setup Time
	            Twlwh:   TIME    :=   15 ns;	-- Write Pulse Width
	            Tdvwh:   TIME    :=   10 ns;	-- Data Valid to End of Write
	            Twhdx:   TIME    :=   0 ns;		-- Data Hold Time
	            Datafile: STRING;
	            MemoryUpdate: Boolean := TRUE);

    PORT ( E_b, 
           W_b, 
           G_b,
           LB_b,
           UB_b: IN Std_Logic;
           A   : IN Std_Logic_Vector(19 downto 0);
           DQ  : INOUT Std_Logic_Vector(15 downto 0):=(others=>'Z'));

End MR4A16B;

-- End Entity Description

--============================================================================
-- Architecture for entity MR4A16B
--============================================================================
Architecture Behavioral Of MR4A16B Is

   Type meminstance Is array (1048575 downto 0) of std_logic_vector(15 downto 0);
   Signal rd, rd_lb, rd_ub, wr, oe, ce, we, bel, beh, ce_pipe, we_pipe, r_chk : Std_logic := '0';
   Signal we_chk, ce_chk, wr_sa, wr_sa1 : Std_logic;
   Signal address, A_adr, prev_addr, addr, testaddress7 : Std_Logic_Vector(19 downto 0);
   Signal io_reg, io_val, chumma : Std_Logic_Vector(15 downto 0);
   Signal Testread, Testread1, testread3, testread2, TESTREAD4, testread5 : std_logic;
   
 ---------------------------------------------------------------------
 -- PROCEDURES READ FROM FILE
 ---------------------------------------------------------------------
 PROCEDURE read_from_file ( file_name : STRING; memory : out meminstance) IS
 
 file data_file : text open read_mode is file_name;
 
 VARIABLE L : line;
 VARIABLE LSB_UB, LSB_LB, MSB_UB, MSB_LB : STD_LOGIC_VECTOR(3 downto 0);
 VARIABLE dr : STRING (1 to 5119);
 VARIABLE index_m,i : natural := 0;
 VARIABLE ROWSIZE: Integer := 1024;
 
 BEGIN
 
 WHILE NOT endfile(data_file) LOOP
 
 readline(data_file,L);
 READ(L,dr);
 deallocate(L);
 
 FOR i IN 1 TO ROWSIZE LOOP
 
 CASE dr((i-1)*5 + 1) IS 
 WHEN '0'=> MSB_UB := "0000";
 WHEN '1'=> MSB_UB := "0001";
 WHEN '2'=> MSB_UB := "0010";
 WHEN '3'=> MSB_UB := "0011";
 WHEN '4'=> MSB_UB := "0100";
 WHEN '5'=> MSB_UB := "0101";
 WHEN '6'=> MSB_UB := "0110";
 WHEN '7'=> MSB_UB := "0111";
 WHEN '8'=> MSB_UB := "1000";
 WHEN '9'=> MSB_UB := "1001";
 WHEN 'A'=> MSB_UB := "1010";
 WHEN 'B'=> MSB_UB := "1011";
 WHEN 'C'=> MSB_UB := "1100";
 WHEN 'D'=> MSB_UB := "1101";
 WHEN 'E'=> MSB_UB := "1110";
 WHEN 'F'=> MSB_UB := "1111";
 WHEN 'a'=> MSB_UB := "1010";
 WHEN 'b'=> MSB_UB := "1010";
 WHEN 'c'=> MSB_UB := "1100";
 WHEN 'd'=> MSB_UB := "1101";
 WHEN 'e'=> MSB_UB := "1110";
 WHEN 'f'=> MSB_UB := "1111";
 WHEN OTHERS => null;
 END CASE;
 
 CASE dr((i-1)*5 + 2) IS 
 WHEN '0'=> LSB_UB := "0000";
 WHEN '1'=> LSB_UB := "0001";
 WHEN '2'=> LSB_UB := "0010";
 WHEN '3'=> LSB_UB := "0011";
 WHEN '4'=> LSB_UB := "0100";
 WHEN '5'=> LSB_UB := "0101";
 WHEN '6'=> LSB_UB := "0110";
 WHEN '7'=> LSB_UB := "0111";
 WHEN '8'=> LSB_UB := "1000";
 WHEN '9'=> LSB_UB := "1001";
 WHEN 'A'=> LSB_UB := "1010";
 WHEN 'B'=> LSB_UB := "1011";
 WHEN 'C'=> LSB_UB := "1100";
 WHEN 'D'=> LSB_UB := "1101";
 WHEN 'E'=> LSB_UB := "1110";
 WHEN 'F'=> LSB_UB := "1111";
 WHEN 'a'=> LSB_UB := "1010";
 WHEN 'b'=> LSB_UB := "1010";
 WHEN 'c'=> LSB_UB := "1100";
 WHEN 'd'=> LSB_UB := "1101";
 WHEN 'e'=> LSB_UB := "1110";
 WHEN 'f'=> LSB_UB := "1111";
 WHEN OTHERS => null;
 END CASE;
 
  CASE dr((i-1)*5 + 3) IS 
  WHEN '0'=> MSB_LB := "0000";
  WHEN '1'=> MSB_LB := "0001";
  WHEN '2'=> MSB_LB := "0010";
  WHEN '3'=> MSB_LB := "0011";
  WHEN '4'=> MSB_LB := "0100";
  WHEN '5'=> MSB_LB := "0101";
  WHEN '6'=> MSB_LB := "0110";
  WHEN '7'=> MSB_LB := "0111";
  WHEN '8'=> MSB_LB := "1000";
  WHEN '9'=> MSB_LB := "1001";
  WHEN 'A'=> MSB_LB := "1010";
  WHEN 'B'=> MSB_LB := "1011";
  WHEN 'C'=> MSB_LB := "1100";
  WHEN 'D'=> MSB_LB := "1101";
  WHEN 'E'=> MSB_LB := "1110";
  WHEN 'F'=> MSB_LB := "1111";
  WHEN 'a'=> MSB_LB := "1010";
  WHEN 'b'=> MSB_LB := "1010";
  WHEN 'c'=> MSB_LB := "1100";
  WHEN 'd'=> MSB_LB := "1101";
  WHEN 'e'=> MSB_LB := "1110";
  WHEN 'f'=> MSB_LB := "1111";
  WHEN OTHERS => null;
  END CASE;
  
  CASE dr((i-1)*5 + 4) IS 
  WHEN '0'=> LSB_LB := "0000";
  WHEN '1'=> LSB_LB := "0001";
  WHEN '2'=> LSB_LB := "0010";
  WHEN '3'=> LSB_LB := "0011";
  WHEN '4'=> LSB_LB := "0100";
  WHEN '5'=> LSB_LB := "0101";
  WHEN '6'=> LSB_LB := "0110";
  WHEN '7'=> LSB_LB := "0111";
  WHEN '8'=> LSB_LB := "1000";
  WHEN '9'=> LSB_LB := "1001";
  WHEN 'A'=> LSB_LB := "1010";
  WHEN 'B'=> LSB_LB := "1011";
  WHEN 'C'=> LSB_LB := "1100";
  WHEN 'D'=> LSB_LB := "1101";
  WHEN 'E'=> LSB_LB := "1110";
  WHEN 'F'=> LSB_LB := "1111";
  WHEN 'a'=> LSB_LB := "1010";
  WHEN 'b'=> LSB_LB := "1010";
  WHEN 'c'=> LSB_LB := "1100";
  WHEN 'd'=> LSB_LB := "1101";
  WHEN 'e'=> LSB_LB := "1110";
  WHEN 'f'=> LSB_LB := "1111";
  WHEN OTHERS => null;
 END CASE;
 
 memory(index_m):=(MSB_UB(3),MSB_UB(2),MSB_UB(1),MSB_UB(0),LSB_UB(3),LSB_UB(2),LSB_UB(1),LSB_UB(0),MSB_LB(3),MSB_LB(2),MSB_LB(1),MSB_LB(0),LSB_LB(3),LSB_LB(2),LSB_LB(1),LSB_LB(0));
 index_m:=index_m+1;
 END LOOP;
 END LOOP;
 
 END read_from_file;
 
 ---------------------------------------------------------------------
 -- PROCEDURES WRITE TO FILE
 ---------------------------------------------------------------------
 PROCEDURE write_to_file (file_name : STRING; memory : IN meminstance) IS
 
 file data_file : text open write_mode is file_name;
 
 VARIABLE L : line;
 VARIABLE LSB_UB, LSB_LB, MSB_UB, MSB_LB : std_logic_vector(3 downto 0);
 VARIABLE dr : STRING (1 to 5119);
 VARIABLE index_m: natural := 0;
 VARIABLE ROWSIZE: Integer := 1024;
 
 BEGIN
 
 WHILE (index_m < 1048576) LOOP
 
 FOR i in 1 TO ROWSIZE LOOP
 
 FOR j IN 0 TO 3 LOOP
 LSB_LB(j):= memory(index_m)(j);
 MSB_LB(j):= memory(index_m)(j+4);
 LSB_UB(j):= memory(index_m)(j+8);
 MSB_UB(j):= memory(index_m)(j+12);
 END LOOP;
 
 index_m:=index_m+1;
 CASE MSB_UB IS 
 WHEN "0000" => dr((i-1)*5 + 1):='0';
 WHEN "0001" => dr((i-1)*5 + 1):='1';
 WHEN "0010" => dr((i-1)*5 + 1):='2';
 WHEN "0011" => dr((i-1)*5 + 1):='3';
 WHEN "0100" => dr((i-1)*5 + 1):='4';
 WHEN "0101" => dr((i-1)*5 + 1):='5';
 WHEN "0110" => dr((i-1)*5 + 1):='6';
 WHEN "0111" => dr((i-1)*5 + 1):='7';
 WHEN "1000" => dr((i-1)*5 + 1):='8';
 WHEN "1001" => dr((i-1)*5 + 1):='9';
 WHEN "1010" => dr((i-1)*5 + 1):='A';
 WHEN "1011" => dr((i-1)*5 + 1):='B';
 WHEN "1100" => dr((i-1)*5 + 1):='C';
 WHEN "1101" => dr((i-1)*5 + 1):='D';
 WHEN "1110" => dr((i-1)*5 + 1):='E';
 WHEN "1111" => dr((i-1)*5 + 1):='F';
 WHEN OTHERS => null;
 END CASE;
 
 CASE LSB_UB IS
 WHEN "0000" => dr((i-1)*5 + 2):='0';
 WHEN "0001" => dr((i-1)*5 + 2):='1';
 WHEN "0010" => dr((i-1)*5 + 2):='2';
 WHEN "0011" => dr((i-1)*5 + 2):='3';
 WHEN "0100" => dr((i-1)*5 + 2):='4';
 WHEN "0101" => dr((i-1)*5 + 2):='5';
 WHEN "0110" => dr((i-1)*5 + 2):='6';
 WHEN "0111" => dr((i-1)*5 + 2):='7';
 WHEN "1000" => dr((i-1)*5 + 2):='8';
 WHEN "1001" => dr((i-1)*5 + 2):='9';
 WHEN "1010" => dr((i-1)*5 + 2):='A';
 WHEN "1011" => dr((i-1)*5 + 2):='B';
 WHEN "1100" => dr((i-1)*5 + 2):='C';
 WHEN "1101" => dr((i-1)*5 + 2):='D';
 WHEN "1110" => dr((i-1)*5 + 2):='E';
 WHEN "1111" => dr((i-1)*5 + 2):='F';
 WHEN OTHERS => null;
 END CASE;
 
  CASE MSB_LB IS
  WHEN "0000" => dr((i-1)*5 + 3):='0';
  WHEN "0001" => dr((i-1)*5 + 3):='1';
  WHEN "0010" => dr((i-1)*5 + 3):='2';
  WHEN "0011" => dr((i-1)*5 + 3):='3';
  WHEN "0100" => dr((i-1)*5 + 3):='4';
  WHEN "0101" => dr((i-1)*5 + 3):='5';
  WHEN "0110" => dr((i-1)*5 + 3):='6';
  WHEN "0111" => dr((i-1)*5 + 3):='7';
  WHEN "1000" => dr((i-1)*5 + 3):='8';
  WHEN "1001" => dr((i-1)*5 + 3):='9';
  WHEN "1010" => dr((i-1)*5 + 3):='A';
  WHEN "1011" => dr((i-1)*5 + 3):='B';
  WHEN "1100" => dr((i-1)*5 + 3):='C';
  WHEN "1101" => dr((i-1)*5 + 3):='D';
  WHEN "1110" => dr((i-1)*5 + 3):='E';
  WHEN "1111" => dr((i-1)*5 + 3):='F';
  WHEN OTHERS => null;
 END CASE;
 
  CASE LSB_LB IS
  WHEN "0000" => dr((i-1)*5 + 4):='0';
  WHEN "0001" => dr((i-1)*5 + 4):='1';
  WHEN "0010" => dr((i-1)*5 + 4):='2';
  WHEN "0011" => dr((i-1)*5 + 4):='3';
  WHEN "0100" => dr((i-1)*5 + 4):='4';
  WHEN "0101" => dr((i-1)*5 + 4):='5';
  WHEN "0110" => dr((i-1)*5 + 4):='6';
  WHEN "0111" => dr((i-1)*5 + 4):='7';
  WHEN "1000" => dr((i-1)*5 + 4):='8';
  WHEN "1001" => dr((i-1)*5 + 4):='9';
  WHEN "1010" => dr((i-1)*5 + 4):='A';
  WHEN "1011" => dr((i-1)*5 + 4):='B';
  WHEN "1100" => dr((i-1)*5 + 4):='C';
  WHEN "1101" => dr((i-1)*5 + 4):='D';
  WHEN "1110" => dr((i-1)*5 + 4):='E';
  WHEN "1111" => dr((i-1)*5 + 4):='F';
  WHEN OTHERS => null;
 END CASE;
 
 if (i < 1024) then dr(5*i) := ' ';end if;
 END LOOP;
 
 WRITE(L,dr);
 writeline(data_file,L);
 END LOOP;
 
END write_to_file;




Begin

-- Signal Assignments from the outside port 
-- RD - Read Signal based on CE/OE and NOT WE
-- WR - Write Signal based on CE and WE

  CE <=  E_b;
  OE <=  G_b;
  WE <=  W_b;
  BEL <= LB_b;
  BEH <= UB_b;
  WR <= (NOT E_b) and (NOT W_b);
  RD <= (NOT E_b) and (NOT G_b) and W_b;
  RD_LB <= (NOT E_b) and (NOT LB_b) and (NOT G_b) and W_b;
  RD_UB <= (NOT E_b) and (NOT UB_b) and (NOT G_b) and W_b;
  io_reg <= DQ;
  address(19 downto 0) <= A(19 downto 0);

--#######################################################################################
-- Process Description for the write and read cycle 
--#######################################################################################
 
 PROCESS (CE, BEL, BEH, OE, WR, RD, IO_REG, Address)
   VARIABLE MRAM_Core: meminstance;
   VARIABLE Troe, Trce, Tro, Trc, Thdrd, Tprev, Tiopr, Tsa1, z : Time := 0 ns;
   VARIABLE wrt, ce_end, wr_end, oe_end, io_end, io_end_high, add_end, bel_end, beh_end, A_event_rd : Std_logic ;
   VARIABLE memoryaddress2, writeinteger : Integer;
   VARIABLE TempAdd1, TempAdd2 : Time;
   VARIABLE first_run : boolean := true;
   VARIABLE MESSAGE : LINE;
   
   begin

 ---------------------------------------
-- initialisation of memory array
---------------------------------------
IF (first_run) THEN
WRITE (message,STRING'("Trying to load"));
--WRITE (message, INIT_FILE);
writeline(output, message);
---------------------------------------
  read_from_file(datafile,MRAM_Core);
  first_run := false;
END IF;
--- Assign signals and variables for time checks before reading or writing.

   ce_pipe <= CE;
   wr_sa <= WR;

   TempAdd1 := A'last_event;
   TempAdd2 := WE'last_event;
   
-- Assignment to Determine Cycle start or End
   if (CE'event and CE'last_value = '1') then
    ce_end := '1';
   else 
    ce_end := '0';
   end if;

-- Assignment to Determine Write Cycle start or End

   if (WR'event and WR'last_value = '1') then
    wr_end := '1';
   else 
    wr_end := '0';
   end if;

-- Assigment for Byte Enable Changes - Low Byte

   if (BEL'event and BEL'last_value = '1') then
    BEL_end := '1';
   else
    BEL_end := '0';
   end if;
 
-- Assigment for Byte Enable Changes - High Bye

   if (BEH'event and BEH'last_value = '1') then
    BEH_end := '1';
   else
    BEH_end := '0';
   end if;
   
-- Assignment to Determine change in IO Pins to determine Setup/Hold timings
   if (io_reg(7 downto 0)'event) then
    io_end := '1';
   else 
    io_end := '0';
   end if;

-- Assignment to Determine change in Address to determine Setup/Hold timings
   if (address'event) then
   Add_end := '1';
   else 
   Add_end := '0';
   end if;

-- Assignment for Output Enable Changes
   if (oe'event and oe'last_value = '1') then
    oe_end := '1';
   else 
    oe_end := '0';
   end if;

------ Storing the last event and previous address when address transitions 
------ along with write end.

   if (Address'event) then
   prev_addr(16 downto 0)  <= address(16 downto 0);
   Tprev := address'last_event;
   end if;
    

------ Storing the address setup to write start time for performing the check 
------ before the write.

   if (wr_end = '1' and Add_end = '1') then
   Tsa1 := Tprev - WR'last_event;
   elsif (wr_end = '1' and Add_end = '0') then
   Tsa1 := Address'last_event -  WR'last_event;
   end if;


----- Reading or writing occurs only when CE low or CE has transitioned 
----- from low to high.

   if ((CE = '0') or (ce_end = '1' and wr_end = '1') or (ce_end = '1')) then
 
      we_pipe <= we;

      wrt := '0';
      if  ((wr'event and wr'last_value = '1') or (ce_end = '1' and wr'last_value = '0')) then 
      wrt := '1';
      else 
      wrt:= '0';
      end if;

------------------------------------------------------------------------------------------------
----- WRITE CYCLE

----- Storing the previous value of higher order data bits and storing last event
----- of data for data setup time check if data changes along with the write end transition.

      if (io_reg'event) then
      io_val <= io_reg;
      Tiopr := io_reg'last_event;
      end if;

    --  if (DQ'event) then
    --  Tiopr := io_reg'last_event;
    --  end if;

----- Write the higher order byte after checking for the necessary
----- timings - Twhax, Tavwl, Tavwh, Tbw, Taw, Tdvwh. 
    
         if (wrt = '1') then
  
  ---------------------------------
  -- Lower Byte Write
  ---------------------------------
                  
          if (we_pipe'last_event >= Tavwl) and (ce_pipe'last_event >= Tavwh) and (Tsa1 >= Twhax) then
             if (Add_end = '1') then
               if (Tprev >= Tavwh) then
                 if (io_end = '1') then
                   if (Tiopr > Tdvwh) then
                     if (BEL = '0') then MRAM_Core(conv_integer(prev_addr))(7 downto 0) := io_val(7 downto 0); end if;
                --    if (MemoryUpdate = TRUE) then write_to_file(datafile,MRAM_Core); end if;
                   end if;
                 else
                   if (DQ'last_event >= Tdvwh) then
                    if (BEL = '0') then MRAM_Core(conv_integer(prev_addr))(7 downto 0) := io_reg (7 downto 0); end if;
                --   if (MemoryUpdate = TRUE) then write_to_file(datafile,MRAM_Core); end if;
                   end if;
                 end if;
               end if;
             else
                if (A'last_event >= Tavwh) then
                  if (io_end = '1') then
                    if (Tiopr >= Tdvwh) then
                      if (BEL = '0') then MRAM_Core(conv_integer(Address))(7 downto 0) := DQ(7 downto 0); end if;
                --     if (MemoryUpdate = TRUE) then write_to_file(datafile,MRAM_Core); end if;
                    end if;
                  else
                    if (DQ'last_event >= Tdvwh) then
                      if (BEL = '0') then MRAM_Core(conv_integer(A))(7 downto 0) := DQ(7 downto 0)(7 downto 0); end if;
                --     if (MemoryUpdate = TRUE)then write_to_file(datafile,MRAM_Core); end if;
                    end if;
                  end if;
                end if;
             end if;
                DQ(15 downto 0) <= "ZZZZZZZZZZZZZZZZ" AFTER Twhdx;
          else
			 ASSERT ( we_pipe'last_event >= Tavwl )
			 REPORT "Tavwl,is = " & time'image(we_pipe'last_event) & "; Tavwl,exp = " & time'image(Tavwl) & "; VALUE NOT WRITTEN TO MRAM"
			 severity warning;
			 
			 ASSERT ( ce_pipe'last_event >= Tavwh )
			 REPORT "Tavwh,is = " & time'image(ce_pipe'last_event) & "; Tavwh,exp = " & time'image(Tavwh) & "; VALUE NOT WRITTEN TO MRAM"
			 severity warning;
			 
			 
			 ASSERT ( Tsa1 >= Twhax )
			 REPORT "Twhax,is = " & time'image(Tsa1) & "; Twhax,exp = " & time'image(Twhax) & "; VALUE NOT WRITTEN TO MRAM"
			 severity warning;
			 
          end if;
  
  ---------------------------------
  -- Upper Byte Write
  ---------------------------------
          
          if (we_pipe'last_event >= Tavwl) and (ce_pipe'last_event >= Tavwh) and (Tsa1 >= Twhax) then
  	           if (Add_end = '1') then
  	             if (Tprev >= Tavwh) then
  	               if (io_end_high = '1') then
  	                 if (Tiopr > Tdvwh) then
  	                   if (BEH =  '0') then MRAM_Core(conv_integer(prev_addr))(15 downto 8) := io_val (15 downto 8); end if;
  	             --     if (MemoryUpdate = TRUE) then write_to_file(datafile,MRAM_Core); end if;
  	                 end if;
  	               else
  	                 if (DQ'last_event >= Tdvwh) then
  	                  if (BEH = '0') then MRAM_Core(conv_integer(prev_addr)) (15 downto 8) := io_reg (15 downto 8); end if;
  	             --    if (MemoryUpdate = TRUE) then write_to_file(datafile,MRAM_Core); end if;
  	                 end if;
  	               end if;
  	             end if;
  	           else
  	              if (A'last_event >= Tavwh) then
  	                if (io_end_high = '1') then
  	                  if (Tiopr >= Tdvwh) then
  	                    if (BEH = '0') then MRAM_Core(conv_integer(Address)) (15 downto 8) := DQ (15 downto 8); end if;
  	             --      if (MemoryUpdate = TRUE) then write_to_file(datafile,MRAM_Core); end if;
  	                  end if;
  	                else
  	                  if (DQ'last_event >= Tdvwh) then
  	                    if (BEH = '0') then MRAM_Core(conv_integer(A)) (15 downto 8) := DQ (15 downto 8); end if;
  	             --      if (MemoryUpdate = TRUE)then write_to_file(datafile,MRAM_Core); end if;
  	                  end if;
  	                end if;
  	              end if;
  	           end if;
  	              DQ(15 downto 0) <= "ZZZZZZZZZZZZZZZZ" AFTER Twhdx;
          end if;
          
          
          
          if (MemoryUpdate = TRUE)then write_to_file(datafile,MRAM_Core); end if;
          
      end if;   


----------------------------------------------------------------------------------------------------
----- READ CYCLE.
-- Read is split into upper byte and lower byte to allow individual byte enable control
----------------------------------------------------------------------------------------------------

    if (Address'event) then
     A_event_rd := '1';
    else
     A_event_rd := '0';
    end if;

------------------------------------------------------------------
-- Read for Lower Byte
------------------------------------------------------------------
------ Determine the read initiation to data valid time.

      if (rd_lb'event and rd_lb = '1') then
        Tro := OE'last_event;
        Troe := Telqv-Tro;
        if (Troe < 0 ns) then
         Troe := 0 ns;
        end if;

       Trc := 0 ns;
       Trc := CE'last_event;
       Trce := Telqv-Trc;
       If (Trce < 0 ns) then
        Trce := 0 ns;
       end if;

       if (Troe > Trce) then
        if (rd = '1') then
        z := Troe;
        end if;
       else
        if (rd = '1') then
        z := Trce;
        end if;
       end if;

       if (address'last_event+z) < Tavqv then
       z := Tavqv;
       end if;
      end if;

  end if;

      if (A_event_rd = '0') then
      testread5 <= '1';
         if (rd_lb'event and rd_lb = '1') then
          TestRead <= '1';
           chumma <= MRAM_core (Conv_integer(A));
           DQ(7 downto 0) <= MRAM_Core(conv_integer(A))(7 downto 0) after z;
         end if;
      elsif (A_event_rd = '1') then
      testread5 <= '0';
        if (rd_lb'event and rd_lb = '1') then
          Testread2 <= '1';
          DQ(7 downto 0) <= MRAM_Core(conv_integer(A))(7 downto 0) after z;
         elsif (rd_lb = '1') then
         testaddress7 <= A;
         memoryaddress2 := conv_integer(A);
          DQ(7 downto 0) <= MRAM_Core(conv_integer(A))(7 downto 0) after Tavqv;
         end if;
      end if;                                                   ------- End Data Out  for Lower Byte

--------------------------------------
-- Read For Lower Byte - Timing Checks
------ Determine read end to High Z time.
------ Check which signal terminates the read
--------------------------------------

       if (rd_lb'event and rd_lb = '0') then

          if (bel = '0' and oe = '0' and ce = '0') then
            
             Thdrd := Tghqz;
             if (Thdrd < Tehqz) then
              Thdrd := Tehqz;
             end if; 
          
          else
             
             if (ce = '0') then
              Thdrd := Tehqz;
             end if;

             if (oe  = '0') then
              Thdrd := Tghqz;
             end if;
             
             if (bel = '0') then
              Thdrd := Tbhqz;
              
          end if;

          if (Thdrd < 0 ns) then
           Thdrd := 0 ns;
          end if;

         DQ(7 downto 0) <= (others=>'Z') after Thdrd; 

      end if;

------------------------------------------------------------------
-- Read for Higher Order Byte
------------------------------------------------------------------
------ Determine the read initiation to data valid time.

      if (rd_ub'event and rd_ub = '1') then
        Tro := OE'last_event;
        Troe := Telqv-Tro;
        if (Troe < 0 ns) then
         Troe := 0 ns;
        end if;

       Trc := 0 ns;
       Trc := CE'last_event;
       Trce := Telqv-Trc;
       If (Trce < 0 ns) then
        Trce := 0 ns;
       end if;

       if (Troe > Trce) then
        if (rd = '1') then
        z := Troe;
        end if;
       else
        if (rd = '1') then
        z := Trce;
        end if;
       end if;

       if (address'last_event+z) < Tavqv then
       z := Tavqv;
       end if;
      end if;

  end if;

      if (A_event_rd = '0') then
      testread5 <= '1';
         if (rd_ub'event and rd_ub = '1') then
          TestRead <= '1';
           DQ(15 downto 8) <= MRAM_Core(conv_integer(A))(15 downto 8) after z;
         end if;
      elsif (A_event_rd = '1') then
      testread5 <= '0';
        if (rd_ub'event and rd = '1') then
          Testread2 <= '1';
          DQ(15 downto 8) <= MRAM_Core(conv_integer(A))(15 downto 8) after z;
         elsif (rd_ub = '1') then
         testaddress7 <= A;
         memoryaddress2 := conv_integer(A);
          DQ(15 downto 8) <= MRAM_Core(conv_integer(A))(15 downto 8) after Tavqv;
         end if;
      end if;                                                   ------- End of Data Out for Higher Order Byte

--------------------------------------
-- Read For High Byte - Timing Checks
------ Determine read end to High Z time.
------ Check which signal terminates the read
--------------------------------------

       if (rd_ub'event and rd_ub = '0') then

          if (beh = '0' and oe = '0' and ce = '0') then
          
             Thdrd := Tghqz;
             if (Thdrd < Tehqz) then
              Thdrd := Tehqz;
             end if; 
          
          else
             
             if (ce = '0') then
              Thdrd := Tehqz;
             end if;

             if (oe  = '0') then
              Thdrd := Tghqz;
             end if;
             
             if (beh = '0') then
              Thdrd := Tbhqz;
             end if;
             
          end if;

          if (Thdrd < 0 ns) then
           Thdrd := 0 ns;
          end if;

         DQ(15 downto 8) <= (others=>'Z') after Thdrd; 

      end if;

      
 END PROCESS;

  
--#######################################################################################
-- Read Cycle (Tavav) and Write Cycle (Tehqz) time checks.
--#######################################################################################

Process (A, address, wr, rd)

variable A_evnt, A_wr, A_rd, r1 : Std_logic;
variable Trd, Tadr : Time;

 Begin

   r_chk <= rd;

   if (A'event) then
   A_adr(16 downto 0)  <= address(16 downto 0);
   end if;

   if (A'event) then
   Tadr := A_adr(16 downto 0)'last_event;
   end if;

   if (wr'event and wr'last_value = '1') then
     A_wr := '1';
   end if;

   if (rd'event and rd'last_value = '1') then
     A_rd := '1';
     Trd := r_chk'last_event;
   end if;

   if address'event then
     A_evnt := '1';
   else
     A_evnt := '0';
   end if;


      if (rd'event and rd'last_value = '1') then
        if (A_evnt = '1') then
        r1 := '1';
        ASSERT (Trd >= Tavav) or (A_adr'LAST_EVENT >= Tavav) 
        REPORT "READ CYCLE TIME VIOLATION"
        SEVERITY Error;   
        elsif (A_evnt = '0') then
        r1 := '0';
        ASSERT (Trd >= Tavav) or (A'LAST_EVENT >= Tavav) 
        REPORT "READ CYCLE TIME VIOLATION"
        SEVERITY Error;   
        end if;
      end if;

      if (A_evnt = '1') then
       if (rd'event and rd'last_value = '1') then
        r1 := '0';
        
       elsif (rd'Last_value = '1' and rd = '1' )then
        ASSERT (A_adr'LAST_EVENT >= Tavav)
        REPORT "READ CYCLE TIME VIOLATION - ADDRESS SWITCH"
        SEVERITY Error; 
        
       elsif (rd'event and rd'last_value = '1') then
        ASSERT (Trd >= Tavav)
        REPORT "READ CYCLE TIME VIOLATION - SHORTENED TERMINATION"
        SEVERITY Error;  
         
      end if;

      if (wr'event and wr'last_value = '1') then
        ASSERT (Tadr >= Tehqz)
        REPORT "WRITE CYCLE TIME VIOLATION"
        SEVERITY Error;   
      elsif A_wr = '1' then
        ASSERT (Tadr >= Tehqz)
        REPORT "WRITE CYCLE TIME VIOLATION"
        SEVERITY Error;   
      end if;

   A_wr := '0';
   A_rd := '0';
   end if;

 End Process;


--#######################################################################################
-- Checks for Tavav, Tavwh, Twhax, Tavwl, Tdvwh and Tbw.
--####################################################################################### 

 Process (ce, wr, W_b, A, DQ)

 VARIABLE wr_end_chk, A_end : Std_logic := '0';
 VARIABLE Taw_chk, Tsd_chk, Tsa_chk, TempAdd3, TempAdd4 : Time;

 begin

   ce_chk <= ce;
   we_chk <= we;
   addr(16 downto 0) <= address(16 downto 0);
   wr_sa1 <= wr;

   wr_end_chk := '0';
   if (wr'event and wr'last_value = '1') then
    wr_end_chk := '1';
   else 
    wr_end_chk := '0';
   end if;

   A_end := '0';
   if (address'event) and (wr_end_chk = '1') then
   A_end := '1';
   else 
    A_end := '0';
   end if;

   if (A'event) then
    Taw_chk := address'last_event;
   end if; 

   if (DQ'event) then
    Tsd_chk := io_reg'last_event;
   end if; 

   if (wr_end_chk = '1' and A_end = '1') then
   tempadd3 := wr'last_event;
   Tsa_chk := Taw_chk - wr'last_event;
   elsif (wr_end_chk = '1' and A_end = '0') then
   Tsa_chk := A'last_event -  wr'last_event;
   end if;

      if wr_end_chk = '1' then
         -- tempadd3 := ce'last_event;
         -- ASSERT (ce'LAST_EVENT >= Tavav)
         -- REPORT "CE LOW TO WRITE END TIME VIOLATION"
         -- SEVERITY Error;

          if (we'event) then
          ASSERT (we_chk'LAST_EVENT >= Tavwl)
          REPORT "WE PULSE WIDTH TIME VIOLATION"
          SEVERITY Error;
          else
          ASSERT (W_b'LAST_EVENT >= Tavwl)
          REPORT "WE PULSE WIDTH TIME VIOLATION"
          SEVERITY Error;
          end if;

          if (A_end = '1') then
          ASSERT (Taw_chk >= Teleh)
          REPORT "ADDRESS SETUP TO WRITE END TIME VIOLATION"
          SEVERITY Error;
          else
          ASSERT (A'LAST_EVENT >= Teleh)
          REPORT "ADDRESS SETUP TO WRITE END TIME VIOLATION"
          SEVERITY Error;
          end if;

          if (io_reg'event) then
           ASSERT (Tsd_chk >= Tdvwh)
           REPORT "DATA SETUP TO WRITE END TIME VIOLATION"
           SEVERITY Error;
          else 
           ASSERT (DQ'LAST_EVENT >= Tdvwh)
           REPORT "DATA SETUP TO WRITE END TIME VIOLATION"
           SEVERITY Error;
          end if;

          ASSERT (Tsa_chk >= Twhax) or (Tsa_chk < 0 ns)
          REPORT "ADDRESS SETUP TO WRITE START TIME VIOLATION, Tsa_chk = " & time'image(Tsa_chk) & "; Twhax = " & time'image(Twhax)
          SEVERITY Error; 
      end if;

   end Process;

--#######################################################################################
-- Address Hold (Tavwh) and Data Hold (Twhdx) time checks on write.
--####################################################################################### 

Process (wr'delayed(Twhdx), wr, A'delayed(Tavwh), DQ)
    begin

     if (wr'delayed(Twhdx) = '0' and wr'delayed(Twhdx)'last_value = '1') and (wr'delayed(Twhdx)'event) then
         ASSERT (DQ'LAST_EVENT = 0 ns) or (DQ'LAST_EVENT > Twhdx)
         REPORT "DATA HOLD FROM WRITE END TIME VIOLATION"
         SEVERITY Error;
     end if;
 
     if (wr = '0' and wr'last_value = '1') and (wr'event) then
         ASSERT (A'delayed(Tavwh)'LAST_EVENT = 0 ns) or (A'LAST_EVENT > Tavwh)
         REPORT "ADDRESS HOLD FROM WRITE END TIME VIOLATION."
         SEVERITY Error;
     end if;
 
   End Process;


--#######################################################################################
-- Telqv, Tdbe, Telqv, Tavqv and Taxqx time checks on read.
--####################################################################################### 

Process (DQ, A'delayed(Taxqx))
    begin

      if ((DQ'event) and (rd = '1')) then
        
          if (rd'last_event <= A'last_event) then
           ASSERT (G_b'LAST_EVENT >= Telqv)
           REPORT "OE LOW TO DATA VALID TIME VIOLATION"
           SEVERITY Error;

           ASSERT (E_b'LAST_EVENT >= Telqv)
           REPORT "CE LOW TO DATA VALID TIME VIOLATION"
           SEVERITY Error;
          end if;

          if (rd'last_event > A'last_event) then
           ASSERT (A'LAST_EVENT >= Tavqv)
           REPORT "ADDRESS TO DATA VALID TIME VIOLATION"
           SEVERITY Error;
          end if;

      end if;

     if (A'delayed(Taxqx)'event and (rd = '1')) then

      if (rd'last_event > Taxqx) then
         ASSERT (DQ'LAST_EVENT = 0 ns) or (DQ'LAST_EVENT > Taxqx)
         REPORT "DATA HOLD FROM ADDRESS CHANGE TIME VIOLATION"
         SEVERITY Error;
      end if;

    end if;

End Process;
             
End Behavioral;






