-- Model Name : Utility Modeling - Memory -- Author : Armita Peymandoust -- Last Updated : 09 / 15 / 1996 -- This document is © copyrighted by the Author.

    
    LIBRARY IEEE;
    USE IEEE.std_logic_1164.ALL;
    
    LIBRARY WORK;
    USE WORK.mem_pack.ALL;
    
    LIBRARY STD;
    USE STD.textio.ALL;
    
    ENTITY ram IS
      
      GENERIC ( no_of_address_bits : POSITIVE := 20;
                no_of_data_bits    : POSITIVE := 32;
                no_of_pages        : POSITIVE := 2 ;
                max_bits           : POSITIVE := 15;  
                -- the maximum of address bits that are used not masked
                file_name          : STRING (1 TO 4) := "PAGE"
              );
    
      PORT ( address   : IN std_logic_vector(no_of_address_bits-1 DOWNTO 0):=(others=>'Z');
             r_wbar    : IN std_logic := '1';
             cs        : IN std_logic := '0';
             data      : INOUT std_logic_vector(no_of_data_bits-1 DOWNTO 0):=(OTHERS=>'Z');
             dump      : IN BOOLEAN := FALSE
           );
    
    
      CONSTANT max      : POSITIVE := (2**max_bits)-1; 
    
      TYPE    n_way       IS ARRAY (1 TO no_of_pages) OF NATURAL;
      SUBTYPE mem_word    IS std_logic_vector(no_of_data_bits-1 DOWNTO 0);
    
      SUBTYPE mem_coded   IS string(round(no_of_data_bits,7) DOWNTO 1);
      CONSTANT all_zeros : mem_coded := (others=>'0');
    
      TYPE    page_type   IS ARRAY (1 TO no_of_pages, 0 TO max ) OF mem_coded;
      SUBTYPE lru_type    IS natural_vector (1 TO no_of_pages);
      TYPE    dirty_table IS ARRAY (1 TO no_of_pages) OF BIT;
      
    END ram;
    
    ARCHITECTURE n_way_paging_6 OF ram IS
        
    BEGIN
      
      PROCESS (address, r_wbar, cs, dump)
    
        VARIABLE lru_table     : lru_type := (others => 0);
        VARIABLE page_table    : n_way := (others => NATURAL'HIGH);
        VARIABLE page_no       : NATURAL;
        VARIABLE chosen_page   : POSITIVE;
        VARIABLE page          : page_type:=(others=>(others=>all_zeros));
        VARIABLE data_v        : mem_word;
        VARIABLE dirty_bits    : dirty_table;       -- these values should be '0' at the begining   
        VARIABLE valid         : BIT_VECTOR(1 TO no_of_pages); 
    
        VARIABLE found         : BOOLEAN;
        VARIABLE replace_found : BOOLEAN;
    
        FILE     f             : TEXT;  
        VARIABLE l             : LINE;
        VARIABLE status        : FILE_OPEN_STATUS := NAME_ERROR;
           
    
      BEGIN
    
        IF dump THEN
    
          FOR i IN page_table'RANGE LOOP
            IF (dirty_bits(i)='1' AND valid(i)='1') THEN
              FILE_OPEN(f, file_name & int2str(page_table(i)) & ".RAM", WRITE_MODE);
              FOR h IN 0 TO max LOOP 
                write(l,page(i, h),RIGHT);
                writeline(f, l);          
              END LOOP;
              FILE_CLOSE(F);                                          
            END IF;
          END LOOP;
    
          
        ELSIF (cs='1') THEN 
    
          page_no := std_logic2int(address( no_of_address_bits-1 DOWNTO max_bits));
    
          FOR i IN lru_table'RANGE LOOP
            lru_table(i) := lru_table(i) + 1;
          END LOOP;
    
          found := FALSE;
          FOR i IN page_table'RANGE LOOP
            IF (page_no = page_table(i) AND 
                valid(i) = '1') THEN
              chosen_page := i;
              found := TRUE;
              EXIT;    
            END IF;
          END LOOP;
          
          IF found = FALSE THEN   -- page fault
    
            replace_found := FALSE;
    
            FOR i IN page_table'RANGE LOOP
              IF valid(i) = '0' THEN
                chosen_page := i;
                replace_found := TRUE;
                EXIT;    
              END IF;
            END LOOP;
    
            IF replace_found=FALSE THEN
              chosen_page := max_of(lru_table);
            END IF;
    
    
            -- WRITE THE FILE BACK
            IF (dirty_bits(chosen_page)='1' AND valid(chosen_page)='1') THEN
              FILE_OPEN(f, file_name & int2str(page_table(chosen_page)) & ".RAM", WRITE_MODE);
              FOR h IN 0 TO max LOOP 
                write(l,page(chosen_page, h),RIGHT);
                writeline(f, l);          
              END LOOP;
              FILE_CLOSE(F);                                          
            ELSE 
              valid(chosen_page):='1'; 
            END IF;
            
            FILE_OPEN(status,f, file_name & int2str(page_no) & ".RAM", READ_MODE);
    
            -- READ THE NEW PAGE
            IF (status = OPEN_OK) THEN
              FOR h IN 0 TO max LOOP
                readline(f, l);  
                read(l, page(chosen_page, h));
                DEALLOCATE(l); 
              END LOOP;
              FILE_CLOSE(F);  
            END IF;
    
            dirty_bits(chosen_page):='0';
            page_table(chosen_page):=page_no;
    
          END IF;
      
          IF (r_wbar='1') THEN
            decode(page(chosen_page, std_logic2int(address(max_bits-1 DOWNTO 0))), data_v);
            data <= data_v;
          ELSIF (r_wbar='0') THEN
            data_v := data;
            encode(data_v, page(chosen_page, std_logic2int(address(max_bits-1 DOWNTO 0))));
            dirty_bits(chosen_page):='1'; 
          END IF;
    
          lru_table(chosen_page) := 0;
    
        ELSIF cs='0' THEN
    
          data <= (others => 'Z');
    
        END IF; 
    
      END PROCESS;
    
    END n_way_paging_6;
    
    
    
    








    
    IBRARY IEEE;
    USE IEEE.std_logic_1164.ALL;
    
    LIBRARY WORK;
    USE WORK.mem_pack.ALL;
    
    ENTITY ram_tester IS
    END ram_tester;
    
    
    ARCHITECTURE testing6 OF ram_tester IS
    
      COMPONENT rm 
    
        PORT ( address   : IN std_logic_vector(no_of_address_bits-1 DOWNTO 0):=(others=>'Z');
               r_wbar    : IN std_logic := '1';
               cs        : IN std_logic := '0';
               data      : INOUT std_logic_vector(no_of_data_bits-1 DOWNTO 0):=(OTHERS=>'Z');
               dump      : IN BOOLEAN := FALSE
             );
      END COMPONENT;
    
      FOR ALL : rm USE ENTITY WORK.ram(n_way_paging_6);
    
      SIGNAL ad :  std_logic_vector(20 DOWNTO 0):=(others=>'Z');
      SIGNAL dt :  std_logic_vector(31 DOWNTO 0):=(others=>'Z');
      SIGNAL rw :  std_logic:='1';
      SIGNAL cs :  std_logic:='0';
      SIGNAL dumping : BOOLEAN := FALSE; 
    
    BEGIN
    
      r : rm PORT MAP(ad, rw, cs, dt,dumping);   
    
      PROCESS
      BEGIN
    
          dt <= "11111111111111111111111111111111"; 
          rw <= '0';
          wait for 0 ns;
          ad <= "000000000000000000010";
          cs <= '1';
          wait for 1 ns;
    
          dt <= "00001111111111111111111111111111";
          wait for 0 ns;
          ad <= "111000000000000000010";
          wait for 1 ns;
    
          dt <= "00000000000000000000000000001111";
          wait for 0 ns;
          ad <= "010000000000000000011";
          wait for 1 ns;
    
          dt <= "11110000000000000000000000000000";
          wait for 0 ns;
          ad <= "100000000000000000110";
          wait for 1 ns;
    
          dt <= "11110000000000000000000000001111";
          wait for 0 ns;
          ad <= "110000000000000000111";
          wait for 1 ns;
    
          dt <= "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";
          wait for 1 ns;
    
       
        ad <= "000000000000000000010";
        rw <= '1';
        wait for 1 ns;
    
        ad <= "010000000000000000011";
        wait for 1 ns;
    
        ad <= "100000000000000000110";
        wait for 1 ns;
    
        ad <= "110000000000000000111";
        wait for 1 ns;  
    
        
        ad <= "111000000000000000010";
        wait for 1 ns; 
        
        dumping <= TRUE;    
        wait; 
    
      END PROCESS;
    
    END testing6;