OSDN Git Service

2004-04-29 Dave Brolley <brolley@redhat.com>
authorbrolley <brolley>
Thu, 29 Apr 2004 20:26:08 +0000 (20:26 +0000)
committerbrolley <brolley>
Thu, 29 Apr 2004 20:26:08 +0000 (20:26 +0000)
        * cacheutil.cxx (cache_set::expell_line): Don't update the set here.

2004-04-29  Dave Brolley  <brolley@redhat.com>

        * cache.cxx: Update calls to cache::find.
        * cacheutil.cxx (cache_set::allocate_lines): Now takes cache index as
        an argument. Update all callers.
        (cache_set::find): Now returns a pointer to the line, if found. Update
        all callers.
        (cache::find): Ditto.
        (cache_set::expell_line): Update the status of the expelled line.
        * cacheutil.h (cache_line_factory::make_line): Now takes cache index as
        an argument. Update all callers.
        (cache_set::allocate_lines): Now takes cache index as
        an argument. Update all callers.
        (cache_set::find): Now returns a pointer to the line, if found. Update
        all callers.
        (cache::find): Ditto.

2004-04-29  Dave Brolley  <brolley@redhat.com>

        * cacheutil.h (cache_line): Removed copy constructor. Now virtual base
        class.
        (cache_line::operator=): Removed.
        (internal_cache_line): New class implements former cache_line class.
        (cache_set): Now takes cache_line_factory.
        (allocate_lines): New method moves line allocation from the constructor.
        (cache_set::set_line): Now takes reference to cache_line.
        (cache_set::replace_line): Renamed to expell_line. Now returns a pointer
        to the expelled line.
        (cache): Now takes cache_line_factory argument.
        (cache::init): New method moves set allocation from the constructor.
        (cache_set::expell_line): Renamed to expell_line. Now returns a pointer
        to the expelled line.
        (cache_line_factory): New class.
        * cacheutil.cxx (cache_line): Removed copy constructor. Now virtual base
        class.
        (cache_line::operator=): Removed.
        (internal_cache_line): New class implements former cache_line class.
        (cache_set): Now takes cache_line_factory.
        (allocate_lines): New method moves line allocation from the constructor.
        (cache_set::set_line): Now takes reference to cache_line.
        (dummy): Now internal to cache_set::find.
        (cache_set::replace_line): Renamed to expell_line. Now returns a pointer
        to the expelled line.
        (cache): Now takes cache_line_factory argument.
        (cache::init): New method moves set allocation from the constructor.
        (cache_set::expell_line): Renamed to expell_line. Now returns a pointer
        to the expelled line.
        * cache.h (cache_replacement_algorithm::expell): Renamed from 'replace'.
        Returns a pointer to the expelled line. Update specializations.
        (cache_component): Now takes a cache_line_factory as an argument.
        Private data now protected.
        (line_factory): New member of cache_component.
        (~cache_component): Now virtual.
        (CacheCreate): Pass internal_line_factory to cache_component.
        * cache.cxx (line_sizes): Make it static.
        (line_sizes): Ditto.
        (replacement_algorithms): Ditto.
        (internal_line_factory): New static cache_line_factory.
        (cache_component): Now takes a cache_line_factory as an argument. Pass
        the cache line factory to the constructor for acache. Save a reference
        to the line factory. Call acache.init
        (write_any): Rewrite to use cache::expell_line instead of the former
        cache::replace.
        (read_any): Ditto.
        (cache_replacement_algorithm::expell): Renamed from 'replace'. Returns
        a pointer to the expelled line. Update all callers and specializations.
        (CacheCreate): Pass internal_line_factory to cache_component.

sid/component/cache/ChangeLog
sid/component/cache/cache.cxx
sid/component/cache/cache.h
sid/component/cache/cacheutil.cxx
sid/component/cache/cacheutil.h

index 9e96e81..aa9cf8c 100644 (file)
@@ -1,3 +1,75 @@
+2004-04-29  Dave Brolley  <brolley@redhat.com>
+
+       * cacheutil.cxx (cache_set::expell_line): Don't update the set here.
+
+2004-04-29  Dave Brolley  <brolley@redhat.com>
+
+       * cache.cxx: Update calls to cache::find.
+       * cacheutil.cxx (cache_set::allocate_lines): Now takes cache index as
+       an argument. Update all callers.
+       (cache_set::find): Now returns a pointer to the line, if found. Update
+       all callers.
+       (cache::find): Ditto.
+       (cache_set::expell_line): Update the status of the expelled line.
+       * cacheutil.h (cache_line_factory::make_line): Now takes cache index as
+       an argument. Update all callers.
+       (cache_set::allocate_lines): Now takes cache index as
+       an argument. Update all callers.
+       (cache_set::find): Now returns a pointer to the line, if found. Update
+       all callers.
+       (cache::find): Ditto.
+
+2004-04-29  Dave Brolley  <brolley@redhat.com>
+
+       * cacheutil.h (cache_line): Removed copy constructor. Now virtual base
+       class.
+       (cache_line::operator=): Removed.
+       (internal_cache_line): New class implements former cache_line class.
+       (cache_set): Now takes cache_line_factory.
+       (allocate_lines): New method moves line allocation from the constructor.
+       (cache_set::set_line): Now takes reference to cache_line.
+       (cache_set::replace_line): Renamed to expell_line. Now returns a pointer
+       to the expelled line.
+       (cache): Now takes cache_line_factory argument.
+       (cache::init): New method moves set allocation from the constructor.
+       (cache_set::expell_line): Renamed to expell_line. Now returns a pointer
+       to the expelled line.
+       (cache_line_factory): New class.
+       * cacheutil.cxx (cache_line): Removed copy constructor. Now virtual base
+       class.
+       (cache_line::operator=): Removed.
+       (internal_cache_line): New class implements former cache_line class.
+       (cache_set): Now takes cache_line_factory.
+       (allocate_lines): New method moves line allocation from the constructor.
+       (cache_set::set_line): Now takes reference to cache_line.
+       (dummy): Now internal to cache_set::find.
+       (cache_set::replace_line): Renamed to expell_line. Now returns a pointer
+       to the expelled line.
+       (cache): Now takes cache_line_factory argument.
+       (cache::init): New method moves set allocation from the constructor.
+       (cache_set::expell_line): Renamed to expell_line. Now returns a pointer
+       to the expelled line.
+       * cache.h (cache_replacement_algorithm::expell): Renamed from 'replace'.
+       Returns a pointer to the expelled line. Update specializations.
+       (cache_component): Now takes a cache_line_factory as an argument.
+       Private data now protected.
+       (line_factory): New member of cache_component.
+       (~cache_component): Now virtual.
+       (CacheCreate): Pass internal_line_factory to cache_component.
+       * cache.cxx (line_sizes): Make it static.
+       (line_sizes): Ditto.
+       (replacement_algorithms): Ditto.
+       (internal_line_factory): New static cache_line_factory.
+       (cache_component): Now takes a cache_line_factory as an argument. Pass
+       the cache line factory to the constructor for acache. Save a reference
+       to the line factory. Call acache.init
+       (write_any): Rewrite to use cache::expell_line instead of the former
+       cache::replace.
+       (read_any): Ditto.
+       (cache_replacement_algorithm::expell): Renamed from 'replace'. Returns
+       a pointer to the expelled line. Update all callers and specializations.
+       (CacheCreate): Pass internal_line_factory to cache_component.
+
 2003-01-31  Frank Ch. Eigler  <fche@redhat.com>
 
        * log2.h: #undef log2, in case a macro collides with the function.
index f8e6476..d47f5c5 100644 (file)
@@ -1,6 +1,6 @@
 // cache.cxx -- A universal memory cache. -*- C++ -*-
 
-// Copyright (C) 2001, 2002 Red Hat.
+// Copyright (C) 2001, 2002, 2004 Red Hat.
 // This file is part of SID and is licensed under the GPL.
 // See the file COPYING.SID for conditions for redistribution.
 
@@ -26,16 +26,16 @@ using std::endl;
 
 #include "cache.h"
 
-string line_sizes[] =
+static string line_sizes[] =
   { "16", "32", "64", "128" };
 
-string cache_sizes[] =
+static string cache_sizes[] =
   { "1", "2", "4", "8", "16", "32", "64", "128", "256", "512" };
 
-string assocs[] =
+static string assocs[] =
   { "direct", "full", "2way", "4way" };
 
-string replacement_algorithms[] =
+static string replacement_algorithms[] =
   { "lru", "fifo", "random" }; 
 
 // One per replacement policy
@@ -43,12 +43,14 @@ static cache_replacement_null null_replacement;
 static cache_replacement_lru lru_replacement;
 static cache_replacement_fifo fifo_replacement;
 static cache_replacement_random random_replacement;
+static cache_line_factory internal_line_factory;
 
 cache_component::cache_component (unsigned assocy,
                                  unsigned cache_sz, 
                                  unsigned line_sz,
-                                 cache_replacement_algorithm& replacer)
-  :acache (cache_sz, line_sz, assocy, replacer),
+                                 cache_replacement_algorithm& replacer,
+                                 cache_line_factory& factory)
+  :acache (cache_sz, line_sz, assocy, replacer, factory),
    upstream (*this),
    downstream (0),
    report_pin (this, &cache_component::emit_report),
@@ -67,6 +69,7 @@ cache_component::cache_component (unsigned assocy,
    write_through_p (false),
    collect_p (true),
    report_heading ("cache profile report"),
+   line_factory (factory),
    line_size (line_sz),
    cache_size (cache_sz),
    assoc (assocy),
@@ -75,6 +78,7 @@ cache_component::cache_component (unsigned assocy,
    refill_latency (0),
    refill_latency_specified (false)
 {
+  acache.init ();
   memset (&stats, 0, sizeof (stats));
 
   add_bus ("upstream", &upstream);
@@ -168,7 +172,6 @@ template <typename DataType>
 bus::status
 cache_component::write_any (host_int_4 addr, DataType data)
 {
-  bool hit;
   bus::status st, read_status;
 
   if (UNLIKELY (downstream == 0))
@@ -177,22 +180,23 @@ cache_component::write_any (host_int_4 addr, DataType data)
   if (LIKELY (collect_p))
     stats.writes++;
 
+  cache_tag tag = acache.addr_to_tag (addr);
   if (UNLIKELY (addr % sizeof (data) != 0))
     {
       // Punt on misaligned accesses
       if (LIKELY (collect_p))
        stats.misaligned_writes++;
 
-      cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
-      if (hit)
+      cache_line* line = acache.find (tag);
+      if (line)
       {
-       if (line.dirty_p ())
+       if (line->dirty_p ())
         {      
          // flush a dirty line being replaced
-         if ((st = write_line (line)) != bus::ok)
+         if ((st = write_line (*line)) != bus::ok)
            return st;
        }
-       acache.expunge (line);
+       acache.expunge (*line);
       }
 
       st = downstream->read (addr, data);
@@ -200,12 +204,12 @@ cache_component::write_any (host_int_4 addr, DataType data)
       return st;
     }
 
-  cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
-  if (LIKELY (hit))
+  cache_line* line = acache.find (tag);
+  if (LIKELY (line))
     {
       if (LIKELY (collect_p))
        stats.write_hits++;
-      line.insert (line_offset (line, addr), data);
+      line->insert (line_offset (*line, addr), data);
       if (write_through_p)
        {
          if ((st = downstream->write (addr, data)) != bus::ok)
@@ -214,34 +218,34 @@ cache_component::write_any (host_int_4 addr, DataType data)
     }
   else
     {
-      if (write_allocate_p)
+      if (write_allocate_p && acache.vacancy_p (addr))
        {
-         if (acache.vacancy_p (addr))
+         if (collect_p)
+           stats.replacements++;
+
+         cache_line *expelled_line = acache.expell_line (tag);
+         assert (expelled_line);
+
+         if (! write_through_p)
            {
-             cache_line expelled_line (line_size);
-             cache_line new_line (line_size, acache.addr_to_tag (addr));
-             if ((read_status = read_line (new_line)) != bus::ok)
-               return read_status;
-             
-             new_line.insert (line_offset (new_line, addr), data);
-             acache.replace (expelled_line, new_line);
-             
-             if (collect_p)
-               stats.replacements++;
-             
-             if (expelled_line.dirty_p () && !write_through_p)
+             if (expelled_line->dirty_p ())
                {
                  // flush a dirty line being replaced
-                 if ((st = write_line (expelled_line)) != bus::ok)
-                   return st;
-               }
-             
-             if (write_through_p)
-               {
-                 if ((st = downstream->write (addr, data)) != bus::ok)
+                 if ((st = write_line (*expelled_line)) != bus::ok)
                    return st;
                }
            }
+         else
+           {
+             if ((st = downstream->write (addr, data)) != bus::ok)
+               return st;
+           }
+
+         expelled_line->set_tag (tag);
+         if ((read_status = read_line (*expelled_line)) != bus::ok)
+           return read_status;
+             
+         expelled_line->insert (line_offset (*expelled_line, addr), data);
        }
       else
        {
@@ -252,7 +256,7 @@ cache_component::write_any (host_int_4 addr, DataType data)
     }
 
   st = bus::ok;
-  if (hit)
+  if (line)
     st.latency = hit_latency;
   else
     st.latency = read_status.latency + miss_latency;
@@ -282,36 +286,34 @@ cache_component::read_any (host_int_4 addr, DataType& data)
       return st;
     }
 
-  bool hit;
-  cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
-  if (LIKELY (hit))
+  cache_tag tag = acache.addr_to_tag (addr);
+  cache_line* line = acache.find (tag);
+  if (LIKELY (line))
     {
       if (LIKELY (collect_p))
        stats.read_hits++;
-      line.extract (line_offset (line, addr), data);
+      line->extract (line_offset (*line, addr), data);
     }
   else
     {
       // miss!
       if (acache.vacancy_p (addr))
        {
-         cache_line expelled_line (line_size);
-         cache_line new_line (line_size, acache.addr_to_tag (addr));
-
-         if ((read_status = read_line (new_line)) != bus::ok)
-           return read_status;
-         new_line.extract (line_offset (new_line, addr), data);
-         acache.replace (expelled_line, new_line);
-
-         if (collect_p)
+         if (LIKELY (collect_p))
            stats.replacements++;
          
-         if (expelled_line.dirty_p ())
+         cache_line *expelled_line = acache.expell_line (tag);
+         assert (expelled_line);
+         if (expelled_line->dirty_p ())
            {
              // flush a dirty line being replaced
-             if ((st = write_line (expelled_line)) != bus::ok)
+             if ((st = write_line (*expelled_line)) != bus::ok)
                  return st;
            }
+         expelled_line->set_tag (tag);
+         if ((read_status = read_line (*expelled_line)) != bus::ok)
+           return read_status;
+         expelled_line->extract (line_offset (*expelled_line, addr), data);
        }
       else
        {
@@ -322,7 +324,7 @@ cache_component::read_any (host_int_4 addr, DataType& data)
     }
 
   st = bus::ok;
-  if (hit)
+  if (line)
     st.latency += hit_latency;
   else
     st.latency = read_status.latency + miss_latency;
@@ -391,10 +393,9 @@ cache_component::flush_all_lines (host_int_4)
 void
 cache_component::flush_line (host_int_4 addr)
 {
-  bool hit;
-  cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
-  if (hit && line.dirty_p ())
-    (void) write_line (line);
+  cache_line* line = acache.find (acache.addr_to_tag (addr));
+  if (line && line->dirty_p ())
+    (void) write_line (*line);
 }
 
 void
@@ -439,21 +440,19 @@ cache_component::invalidate_all_lines (host_int_4 ignore)
 void
 cache_component::invalidate_line (host_int_4 addr)
 {
-  bool hit;
-  cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
-  if (hit)
-    line.invalidate ();
+  cache_line* line = acache.find (acache.addr_to_tag (addr));
+  if (line)
+    line->invalidate ();
 }
 
 void
 cache_component::flush_and_invalidate_line (host_int_4 addr)
 {
-  bool hit;
-  cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
-  if (hit && line.dirty_p ())
+  cache_line* line = acache.find (acache.addr_to_tag (addr));
+  if (line && line->dirty_p ())
     {
-      (void) write_line (line);
-      line.invalidate ();
+      (void) write_line (*line);
+      line->invalidate ();
     }
 }
 
@@ -473,19 +472,17 @@ cache_component::prefetch_line (host_int_4 addr)
 void
 cache_component::lock_line (host_int_4 addr)
 {
-  bool hit;
-  cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
-  if (hit)
-    line.lock ();
+  cache_line* line = acache.find (acache.addr_to_tag (addr));
+  if (line)
+    line->lock ();
 }
 
 void
 cache_component::unlock_line (host_int_4 addr)
 {
-  bool hit;
-  cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
-  if (hit)
-    line.unlock ();
+  cache_line* line = acache.find (acache.addr_to_tag (addr));
+  if (line)
+    line->unlock ();
 }
 
 void
@@ -602,8 +599,8 @@ cache_component::write_hit_rate ()
     }
 }
 \f
-void
-cache_replacement_fifo::replace (cache_set& cset, cache_line& old_line, cache_line new_line)
+cache_line *
+cache_replacement_fifo::expell (cache_set& cset)
 {
   // If this is the first time through, expand fifo accordingly.
   if (fifo.size () != cset.num_lines ())
@@ -628,20 +625,18 @@ cache_replacement_fifo::replace (cache_set& cset, cache_line& old_line, cache_li
        }
       else 
        {
-         old_line = line;
-         old_line.invalidate ();
-         cset.set_line (i, new_line);
-
          // update state
          fifo[i] = 0;
-         return;
+         return &line;
        }
       n--;
     }
+
+  return 0;
 }
 
-void
-cache_replacement_lru::replace (cache_set& cset, cache_line& old_line, cache_line new_line)
+cache_line *
+cache_replacement_lru::expell (cache_set& cset)
 {
   unsigned oldest = 0;
   int index = -1;
@@ -663,12 +658,10 @@ cache_replacement_lru::replace (cache_set& cset, cache_line& old_line, cache_lin
     }
 
   if (index < 0)
-    return;
-  
-  old_line = cset.get_line (index);
-  old_line.invalidate ();
-  cset.set_line (index, new_line);
+    return 0;
+
   lru[index] = 0;
+  return &cset.get_line (index);
 }
 
 void
@@ -684,31 +677,24 @@ cache_replacement_lru::update (cache_set& cset, cache_line& selected_line)
     }
 }
 
-void
-cache_replacement_null::replace (cache_set& cset, cache_line& old_line, cache_line new_line)
+cache_line *
+cache_replacement_null::expell (cache_set& cset)
 {
   cache_line& line = cset.get_line (0);
   if (!line.locked_p ())
-    {
-      old_line = line;
-      old_line.invalidate ();
-      cset.set_line (0, new_line);
-    }
+    return &line;
+
+  return 0;
 }
 
-void
-cache_replacement_random::replace (cache_set& cset, cache_line& old_line, cache_line new_line)
+cache_line *
+cache_replacement_random::expell (cache_set& cset)
 {
   for (unsigned i = 0; i < cset.num_lines (); i++)
     {
       cache_line& line = cset.get_line (i);
       if (!line.valid_p ())
-       {
-         old_line = line;
-         old_line.invalidate ();
-         cset.set_line (i, new_line);
-         return;
-       }
+       return &line;
     }
 
   unsigned n = cset.num_lines ();
@@ -723,18 +709,13 @@ cache_replacement_random::replace (cache_set& cset, cache_line& old_line, cache_
 
       cache_line& line = cset.get_line (i);
       if (!line.locked_p ())
-       {
-         old_line = line;
-         old_line.invalidate ();
-         cset.set_line (i, new_line);
-         return;
-       }
-      else
-       {
-         candidates[i] = false;
-         n--;
-       }
+       return &line;
+
+      candidates[i] = false;
+      n--;
     }
+
+  return 0;
 }
 
 \f
@@ -782,10 +763,10 @@ CacheCreate (const string& typeName)
   bool match;
 
   if (typeName == "hw-cache-basic")
-    return new cache_component (1, 16384, 32, null_replacement);
+    return new cache_component (1, 16384, 32, null_replacement, internal_line_factory);
 
   if (typeName == "hw-cache-buffer-8")
-    return new cache_component (0, 8, 8, null_replacement);
+    return new cache_component (0, 8, 8, null_replacement, internal_line_factory);
   
   vector<string> parts = sidutil::tokenize (typeName, "-/");
 
@@ -856,14 +837,14 @@ CacheCreate (const string& typeName)
     }
 
   if (assoc == 1)
-    return new cache_component (assoc, cache_sz, line_sz, null_replacement);
+    return new cache_component (assoc, cache_sz, line_sz, null_replacement, internal_line_factory);
   
   if (replace_alg_string == "lru")
-    return new cache_component (assoc, cache_sz, line_sz, lru_replacement);
+    return new cache_component (assoc, cache_sz, line_sz, lru_replacement, internal_line_factory);
   else if (replace_alg_string == "fifo")
-    return new cache_component (assoc, cache_sz, line_sz, fifo_replacement);
+    return new cache_component (assoc, cache_sz, line_sz, fifo_replacement, internal_line_factory);
   else if (replace_alg_string == "random")
-    return new cache_component (assoc, cache_sz, line_sz, random_replacement);
+    return new cache_component (assoc, cache_sz, line_sz, random_replacement, internal_line_factory);
 
   return 0;
 }
index 13fb138..ac50b54 100644 (file)
@@ -1,6 +1,6 @@
 // cache.h -- A universal memory cache. -*- C++ -*-
 
-// Copyright (C) 2001, 2002 Red Hat.
+// Copyright (C) 2001, 2002, 2004 Red Hat.
 // This file is part of SID and is licensed under the GPL.
 // See the file COPYING.SID for conditions for redistribution.
 
@@ -62,7 +62,7 @@ private:
 class cache_replacement_fifo: public cache_replacement_algorithm
 {
 public:
-  void replace (cache_set& cset, cache_line& old_line, cache_line new_line);
+  cache_line *expell (cache_set& set);
 
 private:
   vector <int> fifo;
@@ -73,7 +73,7 @@ private:
 class cache_replacement_lru: public cache_replacement_algorithm
 {
 public:
-  void replace (cache_set& cset, cache_line& old_line, cache_line new_line);
+  cache_line *expell (cache_set& set);
   void update (cache_set& cset, cache_line& selected);
 
 private:
@@ -85,7 +85,7 @@ private:
 class cache_replacement_random: public cache_replacement_algorithm
 {
 public:
-  void replace (cache_set& cset, cache_line& old_line, cache_line new_line);
+  cache_line *expell (cache_set& set);
 };
 
 // Null replacement algorithm; used by direct mapped caches
@@ -93,7 +93,7 @@ public:
 class cache_replacement_null: public cache_replacement_algorithm
 {
 public:
-  void replace (cache_set& cset, cache_line& old_line, cache_line new_line);
+  cache_line *expell (cache_set& set);
 };
 
 \f
@@ -106,9 +106,10 @@ class cache_component: public virtual component,
 {
 public:
   cache_component (unsigned asoctvty, unsigned cache_sz,
-                  unsigned line_sz, cache_replacement_algorithm& replacer);
+                  unsigned line_sz, cache_replacement_algorithm& replacer,
+                  cache_line_factory &line_factory);
 
-  ~cache_component () throw();
+  virtual ~cache_component () throw();
 
   template <typename DataType> bus::status 
   write_any (host_int_4 addr, DataType data);
@@ -116,7 +117,7 @@ public:
   template <typename DataType> bus::status
   read_any (host_int_4 addr, DataType& data);
 
-private:
+protected:
   cache acache;
 
   cache_bus upstream;
@@ -193,6 +194,7 @@ private:
     unsigned long replacements;
   } stats;
 
+  cache_line_factory &line_factory;
   unsigned line_size;
   unsigned cache_size;
   unsigned assoc;
index 71e6317..9efcbff 100644 (file)
@@ -1,6 +1,6 @@
 // cacheutil.cxx -- Helper classes for a generic memory cache. -*- C++ -*-
 
-// Copyright (C) 2001, 2002 Red Hat.
+// Copyright (C) 2001, 2002, 2004 Red Hat.
 // This file is part of SID and is licensed under the GPL.
 // See the file COPYING.SID for conditions for redistribution.
 
@@ -18,35 +18,6 @@ operator== (const cache_line& line, const cache_tag& tag)
   return (line.valid_p () && tag == line.tag ());
 }
 
-cache_line::cache_line (const cache_line& other)
-{
-  size = other.size;
-  valid_bit = other.valid_bit;
-  dirty_bit = other.dirty_bit;
-  lock_bit = other.lock_bit;
-  atag = other.atag;
-  data = new byte [size];
-  memcpy (data, other.data, size);
-}
-
-cache_line&
-cache_line::operator= (const cache_line& other)
-{
-  if (this != &other)
-    {
-      // Beware of self-assignment.
-      size = other.size;
-      valid_bit = other.valid_bit;
-      dirty_bit = other.dirty_bit;
-      lock_bit = other.lock_bit;
-      atag = other.atag;
-      delete [] data;
-      data = new byte [size];
-      memcpy (data, other.data, size);
-    }
-  return *this;
-}
-
 using std::cerr;
 using std::hex;
 using std::setw;
@@ -63,113 +34,118 @@ cache_line::dump () const
   if (valid_p ())  cerr << 'V'; else cerr << '-';
   if (locked_p ()) cerr << 'L'; else cerr << '-';
 
-  cerr << "  " << hex << setw (4) << setfill ('0') << atag << "\t";
-  for (unsigned i = 0; i < size; i++)
-    cerr << setw (2) << setfill ('0') << static_cast<unsigned> (data[i]);
-
+  cerr << "  " << hex << setw (4) << setfill ('0') << tag () << "\t";
+  dump_data ();
   cerr << dec << endl;
 }
 
-cache_line::cache_line (unsigned line_size)
-  :size (line_size), valid_bit (false), dirty_bit (false), lock_bit (false), atag (0)
+void
+internal_cache_line::dump_data () const
 {
-  data = new byte [line_size];
-  memset (data, 0, line_size);
+  for (unsigned i = 0; i < size; i++)
+    cerr << setw (2) << setfill ('0') << static_cast<unsigned> (data[i]);
 }
 
-cache_line::cache_line (unsigned line_size, cache_tag t)
-  :size (line_size), valid_bit (false), dirty_bit (false), lock_bit (false), atag (t)
+internal_cache_line::internal_cache_line (unsigned line_size)
+  :size (line_size), valid_bit (false), dirty_bit (false), lock_bit (false), atag (0)
 {
   data = new byte [line_size];
   memset (data, 0, line_size);
 }
 
-cache_line::cache_line (unsigned line_size, cache_tag t, std::vector <byte> initial_data)
-  :size (line_size), valid_bit (false), dirty_bit (false), lock_bit (false), atag (t)
-{
-  assert (initial_data.size () == line_size);
-  data = new byte [line_size];
-  for (unsigned i = 0; i < line_size; i++)
-    data[i] = initial_data[i];
-}
-
-cache_line::~cache_line ()
+internal_cache_line::~internal_cache_line ()
 {
   delete [] data;
 }
 
 void
-cache_line::dirty ()
+internal_cache_line::dirty ()
 {
   dirty_bit = true;
 }
 
 void
-cache_line::clean ()
+internal_cache_line::clean ()
 {
   dirty_bit = false;
 }
 
 void
-cache_line::validate ()
+internal_cache_line::validate ()
 {
   valid_bit = true;
 }
 
 void
-cache_line::invalidate ()
+internal_cache_line::invalidate ()
 {
   valid_bit = false;
 }
 
 void
-cache_line::lock ()
+internal_cache_line::lock ()
 {
   lock_bit = true;
 }
 
 void
-cache_line::unlock ()
+internal_cache_line::unlock ()
 {
   lock_bit = false;
 }
 
+void
+internal_cache_line::set_tag (cache_tag tag)
+{
+  atag = tag;
+}
+
 cache_tag
-cache_line::tag () const
+internal_cache_line::tag () const
 {
   return atag;
 }
 
 bool
-cache_line::dirty_p () const
+internal_cache_line::dirty_p () const
 {
   return dirty_bit;
 }
 
 bool
-cache_line::valid_p () const
+internal_cache_line::valid_p () const
 {
   return valid_bit;
 }
 
 bool
-cache_line::locked_p () const
+internal_cache_line::locked_p () const
 {
   return lock_bit;
 }
 
-cache_set::cache_set (unsigned line_size, unsigned nlines, cache_replacement_algorithm& alg)
-  :replacer (alg)
+cache_set::cache_set (unsigned line_sz, unsigned nlines, cache_replacement_algorithm& alg, cache_line_factory &f)
+  :replacer (alg),
+   line_factory (f),
+   line_size (line_sz)
 {
   lines.resize (nlines);
   for (iterator_t it = lines.begin(); it != lines.end (); it++)
-    *it = new cache_line (line_size);
+    *it = NULL;
 }
 
 cache_set::~cache_set ()
 {
   for (iterator_t it = lines.begin (); it != lines.end (); it++)
-    delete *it;
+    line_factory.destroy_line (*it);
+}
+
+void
+cache_set::allocate_lines (unsigned index)
+{
+  unsigned way = 0;
+  for (iterator_t it = lines.begin(); it != lines.end (); way++, it++)
+    *it = line_factory.make_line (line_size, index, way);
 }
 
 unsigned
@@ -185,28 +161,25 @@ cache_set::get_line (unsigned i) const
 }
 
 void
-cache_set::set_line (unsigned i, const cache_line line)
+cache_set::set_line (unsigned i, cache_line &line)
 {
-  *lines[i] = line;
+  lines[i] = &line;
 }
 
-cache_line&
-cache_set::find (const cache_tag& tag, bool& hit)
+cache_line*
+cache_set::find (const cache_tag& tag)
 {
-  static cache_line dummy(0);
-
   // Scan the lines in this set for tag. Might as well be linear; the
   // order of associativity will be small.
 
   for (const_iterator_t it = lines.begin (); it != lines.end (); it++)
     if (tag == *(*it))
       {
-       hit = true;
        replacer.update (*this, *(*it));
-       return *(*it);
+       return *it;
       }
-  hit = false;
-  return dummy;
+
+  return NULL;
 }
 
 
@@ -247,10 +220,11 @@ cache_set::expunge_line (cache_line& line)
   line.invalidate ();
 }
 
-void
-cache_set::replace_line (cache_line& old_line, cache_line new_line)
+cache_line *
+cache_set::expell_line ()
 {
-  return replacer.replace (*this, old_line, new_line);
+  cache_line *line = replacer.expell (*this);
+  return line;
 }
 
 void
@@ -261,7 +235,8 @@ cache_set::dump () const
 }
 
 cache::cache (unsigned cache_size, unsigned line_size, unsigned assoc,
-             cache_replacement_algorithm& replacer)
+             cache_replacement_algorithm& replacer,
+             cache_line_factory& line_factory)
 {
   assert (power_of_two_p (line_size));
   assert (cache_size >= line_size);
@@ -284,7 +259,7 @@ cache::cache (unsigned cache_size, unsigned line_size, unsigned assoc,
   int lines_per_set = (assoc == 0) ? num_lines : assoc;
  
   for (iterator_t it = sets.begin (); it != sets.end (); it++)
-    *it = new cache_set (line_size, lines_per_set, replacer);
+    *it = new cache_set (line_size, lines_per_set, replacer, line_factory);
   
   num_non_tag_bits = log2 (line_size);
 
@@ -300,6 +275,14 @@ cache::~cache ()
     delete sets[i];
 }
 
+void
+cache::init ()
+{
+  unsigned index = 0;
+  for (iterator_t it = sets.begin (); it != sets.end (); it++, index++)
+    (*it)->allocate_lines (index);
+}
+  
 cache_tag
 cache::addr_to_tag (const sid::host_int_4& addr) const
 {
@@ -312,11 +295,11 @@ cache::tag_to_addr (const cache_tag& tag) const
   return tag << num_non_tag_bits;
 }
 
-cache_line&
-cache::find (cache_tag tag, bool& hit)
+cache_line*
+cache::find (cache_tag tag)
 {
   unsigned index = hash_fn (tag);
-  return sets[index]->find (tag, hit);
+  return sets[index]->find (tag);
 }
 
 cache_line*
@@ -370,11 +353,11 @@ cache::expunge (cache_line& line)
 // Replace a line in the cache with 'new_line'.  If the expelled
 // line is dirty, set 'old_line' to it and return true, otherwise
 // false.
-void
-cache::replace (cache_line& old_line, cache_line new_line)
+cache_line *
+cache::expell_line (cache_tag tag)
 {
-  unsigned index = hash_fn (new_line.tag ());
-  return sets[index]->replace_line (old_line, new_line);
+  unsigned index = hash_fn (tag);
+  return sets[index]->expell_line ();
 }
 
 unsigned
index 40db5ac..0e27a58 100644 (file)
@@ -1,6 +1,6 @@
 // cacheutil.h -- Helper classes for a generic memory cache. -*- C++ -*-
 
-// Copyright (C) 2001, 2002 Red Hat.
+// Copyright (C) 2001, 2002, 2004 Red Hat.
 // This file is part of SID and is licensed under the GPL.
 // See the file COPYING.SID for conditions for redistribution.
 
 typedef sid::host_int_4 cache_tag;
 typedef sid::host_int_1 byte;
 
-// The cache_line class represents a line in a cache:
+// The cache_line class represents a line in a cache. It is a virtual base
+// class which requires an implementation.
+
+class cache_line
+{
+public:
+  virtual ~cache_line () {}
+
+  // Get the line's tag.
+  virtual void set_tag (cache_tag tag) = 0;
+  virtual cache_tag tag () const = 0;
+
+  // Mark the line dirty or clean.
+  virtual void dirty () = 0;
+  virtual void clean () = 0;
+
+  // Mark the line valid or invalid.
+  virtual void validate () = 0;
+  virtual void invalidate () = 0;
+
+  // Lock or unlock the line.
+  virtual void lock () = 0;
+  virtual void unlock () = 0;
+
+  // Is the line dirty?
+  virtual bool dirty_p () const = 0;
+
+  // Is the line valid?
+  virtual bool valid_p () const = 0;
+
+  // Is the line locked?
+  virtual bool locked_p () const = 0;
+
+  // Insert or extract a datum from the line, starting at byte offset.
+#define DEFN_METHOD(DataType) \
+  virtual void insert (unsigned offset, DataType new_data) = 0; \
+  virtual void extract (unsigned offset, DataType& new_data) const = 0;
+
+  DEFN_METHOD (sid::big_int_1)
+  DEFN_METHOD (sid::big_int_2)
+  DEFN_METHOD (sid::big_int_4)
+  DEFN_METHOD (sid::big_int_8)
+  DEFN_METHOD (sid::little_int_1)
+  DEFN_METHOD (sid::little_int_2)
+  DEFN_METHOD (sid::little_int_4)
+  DEFN_METHOD (sid::little_int_8)
+#undef DEFN_METHOD
+
+  // Dump a line in human readable form to cout.
+  virtual void dump () const;
+  virtual void dump_data () const = 0;
+};
+
+// The internal_cache_line class keeps its data internally and is the default
+// cache_line implementation.
 
 // +-------+-----+----------------+ M = modified (dirty) bit
 // | M V L | tag |     data       | V = valid bit
 // +-------+-----+----------------+ L = lock bit
 //           byte 0              N
 
-class cache_line
+class internal_cache_line : public cache_line
 {
 public:
-  cache_line (unsigned line_size);
-  cache_line (unsigned line_size, cache_tag tag);
-  cache_line (unsigned line_size, cache_tag tag, std::vector <byte> intial_data);
-  cache_line (const cache_line&);
-  cache_line& operator= (const cache_line&);
-  virtual ~cache_line ();
+  internal_cache_line (unsigned line_size);
+  ~internal_cache_line ();
 
   // Get the line's tag.
+  void set_tag (cache_tag tag);
   cache_tag tag () const;
 
   // Mark the line dirty or clean.
@@ -58,28 +109,36 @@ public:
   // Is the line locked?
   bool locked_p () const;
 
-  // Insert a datum into the line, starting at byte offset.
-  template <typename DataType>
-  void insert (unsigned offset, DataType new_data)
-  {
-    assert (offset + sizeof (new_data) <= size);
-    typename DataType::value_type mem_image = new_data.target_memory_value ();
-    memcpy (& data[offset], & mem_image, sizeof (new_data));
-    dirty_bit = true;
+#define DEFN_METHOD(DataType) \
+  /* Insert a datum into the line, starting at byte offset.  */ \
+  virtual void insert (unsigned offset, DataType new_data) \
+  { \
+    assert (offset + sizeof (new_data) <= size); \
+    DataType::value_type mem_image = new_data.target_memory_value (); \
+    memcpy (& data[offset], & mem_image, sizeof (new_data)); \
+    dirty_bit = true; \
+  } \
+  /* Extract a datum from the line, starting at byte offset.  */ \
+  virtual void extract (unsigned offset, DataType& new_data) const \
+  { \
+    assert (offset + sizeof (new_data) <= size); \
+    DataType::value_type mem_image; \
+    memcpy (& mem_image, & data[offset], sizeof (new_data)); \
+    new_data.set_target_memory_value (mem_image); \
   }
 
-  // Extract a datum from the line, starting at byte offset.
-  template <typename DataType>
-  void extract (unsigned offset, DataType& new_data) const
-  {
-    assert (offset + sizeof (new_data) <= size);
-    typename DataType::value_type mem_image;
-    memcpy (& mem_image, & data[offset], sizeof (new_data));
-    new_data.set_target_memory_value (mem_image);
-  }
+  DEFN_METHOD (sid::big_int_1)
+  DEFN_METHOD (sid::big_int_2)
+  DEFN_METHOD (sid::big_int_4)
+  DEFN_METHOD (sid::big_int_8)
+  DEFN_METHOD (sid::little_int_1)
+  DEFN_METHOD (sid::little_int_2)
+  DEFN_METHOD (sid::little_int_4)
+  DEFN_METHOD (sid::little_int_8)
+#undef DEFN_METHOD
 
   // Dump a line in human readable form to cout.
-  void dump () const;
+  void dump_data () const;
 
 private:
   unsigned size;
@@ -102,14 +161,30 @@ class cache_replacement_algorithm
 public:
   virtual ~cache_replacement_algorithm () {}
 
-  // Place new_line in a cache slot. Point old_line to the existing line.
-  // Return true if successful, false otherwise.
-  virtual void replace (cache_set& cset, cache_line& old_line, cache_line new_line) = 0;
+  // Choose a line to replace in a cache set. Return it, if successful
+  virtual cache_line *expell (cache_set &set) = 0;
 
   // Update state (for example, treating LRU bits), if required.
-  virtual void update (cache_set& cset, cache_lineaccessed_line) {}
+  virtual void update (cache_set& cset, cache_line &accessed_line) {}
 };
 
+// The cache_line_factory creates and destroys cache lines. This default
+// implementation creates lines of type internal_cache_line.
+
+class cache_line_factory
+{
+public:
+  virtual ~cache_line_factory () {}
+
+  virtual cache_line *make_line (unsigned line_size, unsigned index, unsigned way)
+  {
+    return new internal_cache_line (line_size);
+  }
+  virtual void destroy_line (cache_line *line)
+  {
+    delete line;
+  }
+};
 
 // The cache_set class represents a set of cache_lines.  For a 2-way
 // associative cache, there will be just two lines in the set.
@@ -118,16 +193,16 @@ class cache_set
 {
 public:
   cache_set (unsigned line_size, unsigned nlines,
-            cache_replacement_algorithm& alg);
+            cache_replacement_algorithm& alg, cache_line_factory &f);
   virtual ~cache_set ();
+
+  void allocate_lines (unsigned index);
+
   // Try to find a line in the cache with a matching tag. 
-  // If found, set "hit" to true and return a ref to the line.
-  // Otherwise, set "hit" to false.
-  virtual cache_line& find (const cache_tag& tag, bool& hit);
+  // If found, return it.
+  virtual cache_line* find (const cache_tag& tag);
 
-  // Find any dirty cache line.  If found, set hit to true and return it.
-  // Otherwise, set hit to false.
+  // Find any dirty cache line.  If found, return the line
   virtual cache_line* find_any_dirty ();
 
   // Invalidate the entire set.
@@ -142,9 +217,8 @@ public:
   // Flush the entire set.
   void expunge (unsigned index);
 
-  // Replace a line in the set with new_line.
-  // Return false if the line cannot be placed, true otherwise.
-  void replace_line (cache_line& old_line, cache_line new_line);
+  // Choose a line to be replaced. Return it, if successful.
+  cache_line *expell_line ();
 
   // Return the number of lines in the set.
   unsigned num_lines () const;
@@ -153,7 +227,7 @@ public:
   cache_line& get_line (unsigned i) const;
 
   // Place a cache line into slot `i' of the set.
-  void set_line (unsigned i, const cache_line line);
+  void set_line (unsigned i, cache_line &line);
 
   // Dump diagnostics to cerr.
   virtual void dump () const;
@@ -166,7 +240,9 @@ public:
 
 private:
   cache_replacement_algorithm& replacer;
+  cache_line_factory& line_factory;
   std::vector <cache_line*> lines;
+  unsigned line_size;
   typedef std::vector <cache_line*>::iterator iterator_t;
   typedef std::vector <cache_line*>::const_iterator const_iterator_t;
 };
@@ -185,18 +261,20 @@ class cache
 {
 public:
   cache (unsigned cache_size, unsigned line_size,
-        unsigned assoc, cache_replacement_algorithm& replacer);
+        unsigned assoc, cache_replacement_algorithm& replacer,
+        cache_line_factory &line_factory);
   virtual ~cache ();
 
+  void init ();
+
   // Calculate a tag.
   cache_tag addr_to_tag (const sid::host_int_4& addr) const;
 
   // Perform the inverse operation.
   sid::host_int_4 tag_to_addr (const cache_tag& tag) const;
   
-  // Find a line, given a tag.  If found, set hit to true and return it.
-  // Otherwise, set hit to false.
-  cache_line& find (cache_tag tag, bool& hit);
+  // Find a line, given a tag.  If found, return it.
+  cache_line* find (cache_tag tag);
 
   // Find any dirty cache line.  If found, set hit to true and return it.
   // Otherwise, set hit to false.
@@ -208,10 +286,9 @@ public:
   // Vacancy in the cache?
   bool vacancy_p (const sid::host_int_4& addr) const;
 
-  // Replace a line in the cache with 'new_line'.  If the expelled
-  // line is dirty, set 'old_line' to it and return true, otherwise
-  // false.
-  void replace (cache_line& old_line, cache_line new_line);
+  // Choose a line in the cache to expell in place of one
+  // representing 'tag'. Return it, if successful.
+  cache_line *expell_line (cache_tag tag);
 
   // Invalidate the entire cache.
   void invalidate ();