dlx/cache-behaviour.vhdl

    1 --------------------------------------------------------------------------
    2 --
    3 --  Copyright (C) 1993, Peter J. Ashenden
    4 --  Mail:	Dept. Computer Science
    5 --		University of Adelaide, SA 5005, Australia
    6 --  e-mail:	petera@cs.adelaide.edu.au
    7 --
    8 --  This program is free software; you can redistribute it and/or modify
    9 --  it under the terms of the GNU General Public License as published by
   10 --  the Free Software Foundation; either version 1, or (at your option)
   11 --  any later version.
   12 --
   13 --  This program is distributed in the hope that it will be useful,
   14 --  but WITHOUT ANY WARRANTY; without even the implied warranty of
   15 --  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16 --  GNU General Public License for more details.
   17 --
   18 --  You should have received a copy of the GNU General Public License
   19 --  along with this program; if not, write to the Free Software
   20 --  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   21 --
   22 --------------------------------------------------------------------------
   23 --
   24 --  $RCSfile: cache-behaviour.vhdl,v $  $Revision: 1.1 $  $Date: 2000/05/08 14:36:47 $
   25 --
   26 --------------------------------------------------------------------------
   27 --
   28 --  Behavioural architecture for cache.
   29 --
   30 
   31 
   32 use work.bv_arithmetic.bv_to_natural,
   33     work.bv_arithmetic.natural_to_bv;
   34 
   35 
   36 architecture behaviour of cache is
   37 
   38 begin  --  behaviour 
   39 
   40   cache_behaviour : process
   41 
   42     constant words_per_line : positive := line_size / 4;
   43     constant number_of_sets : positive := cache_size / line_size / associativity;
   44 
   45     subtype word_offset_range is natural range 0 to words_per_line-1;
   46     subtype entry_index_range is natural range 0 to associativity-1;
   47     subtype set_index_range is natural range 0 to number_of_sets-1;
   48 
   49     type line is array (word_offset_range) of dlx_word;
   50 
   51     type entry is record
   52         tag : natural;
   53         valid : boolean;
   54         dirty : boolean;
   55         data : line;
   56       end record;
   57 
   58     type store_array is array (set_index_range, entry_index_range) of entry;
   59 
   60     variable store : store_array;
   61     variable    cpu_address      : natural;
   62     variable    word_offset      : word_offset_range;
   63     variable    set_index        : set_index_range;
   64     variable    cpu_tag          : natural;
   65     variable    entry_index      : entry_index_range;
   66     variable    hit              : boolean;
   67     variable    next_replacement_entry_index : entry_index_range := 0;
   68 
   69 
   70     procedure do_read_hit is
   71     begin
   72       cpu_d <= store(set_index, entry_index).data(word_offset);
   73       cpu_ready <= '1' after Tpd_clk_out;
   74       wait until phi2 = '0';
   75       cpu_d <= null after Tpd_clk_out;
   76       cpu_ready <= '0' after Tpd_clk_out;
   77     end do_read_hit;
   78 
   79 
   80     procedure do_write_through is
   81     begin
   82       wait until phi1 = '1';
   83       if reset = '1' then
   84         return;
   85       end if;
   86       mem_a <= cpu_a after Tpd_clk_out;
   87       mem_width <= cpu_width after Tpd_clk_out;
   88       mem_d <= cpu_d after Tpd_clk_out;
   89       mem_write <= '1' after Tpd_clk_out;
   90       mem_burst <= '0' after Tpd_clk_out;
   91       mem_enable <= '1' after Tpd_clk_out;
   92       wait until mem_ready = '1' or reset = '1';
   93       cpu_ready <= mem_ready after Tpd_clk_out;
   94       wait until phi2 = '0';
   95       mem_d <= null after Tpd_clk_out;
   96       mem_write <= '0' after Tpd_clk_out;
   97       mem_enable <= '0' after Tpd_clk_out;
   98       cpu_ready <= '0' after Tpd_clk_out;
   99     end do_write_through;
  100 
  101 
  102     procedure do_write_hit is
  103     begin
  104       case cpu_width is
  105         when width_word =>
  106           store(set_index, entry_index).data(word_offset) := cpu_d;
  107         when width_halfword =>
  108           if cpu_a(1) = '0' then  -- ms half word
  109             store(set_index, entry_index).data(word_offset)(0 to 15) := cpu_d(0 to 15);
  110           else  -- ls half word
  111             store(set_index, entry_index).data(word_offset)(16 to 23) := cpu_d(16 to 23);
  112           end if;
  113         when width_byte =>
  114           if cpu_a(1) = '0' then  -- ms half word
  115             if cpu_a(0) = '0' then  -- byte 0
  116               store(set_index, entry_index).data(word_offset)(0 to 7) := cpu_d(0 to 7);
  117             else  -- byte 1
  118               store(set_index, entry_index).data(word_offset)(8 to 15) := cpu_d(8 to 15);
  119             end if;
  120           else  -- ls half word
  121             if cpu_a(0) = '0' then  -- byte 2
  122               store(set_index, entry_index).data(word_offset)(16 to 23) := cpu_d(16 to 23);
  123             else  -- byte 3
  124               store(set_index, entry_index).data(word_offset)(24 to 31) := cpu_d(24 to 31);
  125             end if;
  126           end if;
  127       end case;
  128       if write_strategy = copy_back then
  129         store(set_index, entry_index).dirty := true;
  130       end if;
  131       --
  132       -- if write_through cache, also update main memory
  133       if write_strategy = write_through then
  134         do_write_through;
  135       else  --  copy_back cache
  136         cpu_ready <= '1' after Tpd_clk_out;
  137         wait until phi2 = '0';
  138         cpu_ready <= '0' after Tpd_clk_out;
  139       end if;
  140     end do_write_hit;
  141 
  142 
  143     procedure copy_back_line is
  144       variable next_address : natural;
  145       variable old_word_offset : natural;
  146     begin
  147       next_address := (store(set_index, entry_index).tag * number_of_sets
  148                       + set_index) * line_size;
  149       wait until phi1 = '1';
  150       if reset = '1' then
  151         return;
  152       end if;
  153       mem_width <= width_word after Tpd_clk_out;
  154       mem_write <= '1' after Tpd_clk_out;
  155       mem_enable <= '1' after Tpd_clk_out;
  156       mem_burst <= '1' after Tpd_clk_out;
  157       old_word_offset := 0;
  158       burst_loop : loop
  159         if old_word_offset = words_per_line-1 then
  160           mem_burst <= '0' after Tpd_clk_out;
  161         end if;
  162         mem_a <= natural_to_bv(next_address, mem_a'length) after Tpd_clk_out;
  163         mem_d <= store(set_index, entry_index).data(old_word_offset) after Tpd_clk_out;
  164         wait_loop : loop
  165           wait until phi2 = '0';
  166           exit burst_loop when reset = '1'
  167                           or (mem_ready = '1' and old_word_offset = words_per_line-1);
  168           exit wait_loop when mem_ready = '1';
  169         end loop wait_loop;
  170         old_word_offset := old_word_offset + 1;
  171         next_address := next_address + 4;
  172       end loop burst_loop;
  173       store(set_index, entry_index).dirty := false;
  174       mem_d <= null after Tpd_clk_out;
  175       mem_write <= '0' after Tpd_clk_out;
  176       mem_enable <= '0' after Tpd_clk_out;
  177     end copy_back_line;
  178 
  179 
  180     procedure fetch_line is
  181       variable next_address : natural;
  182       variable new_word_offset : natural;
  183     begin
  184       next_address := (cpu_address / line_size) * line_size;
  185       wait until phi1 = '1';
  186       if reset = '1' then
  187         return;
  188       end if;
  189       mem_width <= width_word after Tpd_clk_out;
  190       mem_write <= '0' after Tpd_clk_out;
  191       mem_enable <= '1' after Tpd_clk_out;
  192       mem_burst <= '1' after Tpd_clk_out;
  193       new_word_offset := 0;
  194       burst_loop : loop
  195         if new_word_offset = words_per_line-1 then
  196           mem_burst <= '0' after Tpd_clk_out;
  197         end if;
  198         mem_a <= natural_to_bv(next_address, mem_a'length) after Tpd_clk_out;
  199         wait_loop : loop
  200           wait until phi2 = '0';
  201           store(set_index, entry_index).data(new_word_offset) := mem_d;
  202           exit burst_loop when reset = '1'
  203                           or (mem_ready = '1' and new_word_offset = words_per_line-1);
  204           exit wait_loop when mem_ready = '1';
  205         end loop wait_loop;
  206         new_word_offset := new_word_offset + 1;
  207         next_address := next_address + 4;
  208       end loop burst_loop;
  209       store(set_index, entry_index).valid := true;
  210       store(set_index, entry_index).tag := cpu_tag;
  211       store(set_index, entry_index).dirty := false;
  212       mem_enable <= '0' after Tpd_clk_out;
  213     end fetch_line;
  214 
  215 
  216     procedure replace_line is
  217     begin
  218       --  first chose an entry using "random" number generator
  219       entry_index := next_replacement_entry_index;
  220       next_replacement_entry_index
  221         := (next_replacement_entry_index + 1) mod associativity;
  222       if store(set_index, entry_index).dirty then
  223         copy_back_line;
  224       end if;
  225       fetch_line;
  226     end replace_line;
  227 
  228 
  229     procedure do_read_miss is
  230     begin
  231       replace_line;
  232       if reset = '1' then
  233         return;
  234       end if;
  235       do_read_hit;
  236     end do_read_miss;
  237 
  238 
  239     procedure do_write_miss is
  240     begin
  241       -- if write_through cache, just update main memory
  242       if write_strategy = write_through then
  243         do_write_through;
  244       else  --  copy_back cache
  245         replace_line;
  246         if reset = '1' then
  247           return;
  248         end if;
  249         do_write_hit;
  250       end if;
  251     end do_write_miss;
  252 
  253 
  254   begin  --  process cache_behaviour 
  255     --  reset: initialize outputs and the cache store valid bits
  256     cpu_ready <= '0';
  257     cpu_d <= null;
  258     mem_enable <= '0';
  259     mem_width <= width_word;
  260     mem_write <= '0';
  261     mem_burst <= '0';
  262     mem_a <= X"00000000";
  263     mem_d <= null;
  264     for init_set_index in set_index_range loop
  265       for init_entry_index in entry_index_range loop
  266         store(init_set_index, init_entry_index).valid := false;
  267         store(init_set_index, init_entry_index).dirty := false;
  268       end loop;                          --  init_entry_index
  269     end loop;                            --  init_set_index
  270     --  
  271     loop
  272       --  wait for a cpu request
  273       wait until phi2 = '1' and cpu_enable = '1';
  274       --  decode address
  275       cpu_address := bv_to_natural(cpu_a);
  276       word_offset := (cpu_address mod line_size) / 4;
  277       set_index := (cpu_address / line_size) mod number_of_sets;
  278       cpu_tag := cpu_address / line_size / number_of_sets;
  279       --  check for hit
  280       hit := false;
  281       for lookup_entry_index in entry_index_range loop
  282         if store(set_index, lookup_entry_index).valid
  283             and store(set_index, lookup_entry_index).tag = cpu_tag then
  284           hit := true;
  285           entry_index := lookup_entry_index;
  286           exit;
  287         end if;
  288       end loop;                          --  lookup_entry
  289       --
  290       if hit then
  291         if cpu_write = '1' then
  292           do_write_hit;
  293         else
  294           do_read_hit;
  295         end if;
  296       else
  297         if cpu_write = '1' then
  298           do_write_miss;
  299         else
  300           do_read_miss;
  301         end if;
  302       end if;
  303       exit when reset = '1';
  304     end loop;
  305     --  loop exited on reset: wait until it goes inactive
  306     --  then start again
  307     wait until phi2 = '0' and reset = '0';
  308   end process cache_behaviour;
  309 
  310 end behaviour;
  311 

This page was generated using GHDL 0.14 (20040829) [Sokcho edition], a program written by Tristan Gingold