* 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.
+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.
// 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.
#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
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),
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),
refill_latency (0),
refill_latency_specified (false)
{
+ acache.init ();
memset (&stats, 0, sizeof (stats));
add_bus ("upstream", &upstream);
bus::status
cache_component::write_any (host_int_4 addr, DataType data)
{
- bool hit;
bus::status st, read_status;
if (UNLIKELY (downstream == 0))
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);
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)
}
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
{
}
st = bus::ok;
- if (hit)
+ if (line)
st.latency = hit_latency;
else
st.latency = read_status.latency + miss_latency;
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
{
}
st = bus::ok;
- if (hit)
+ if (line)
st.latency += hit_latency;
else
st.latency = read_status.latency + miss_latency;
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
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 ();
}
}
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
}
}
\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 ())
}
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;
}
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
}
}
-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 ();
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
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, "-/");
}
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;
}
// 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.
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;
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:
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
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
{
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);
template <typename DataType> bus::status
read_any (host_int_4 addr, DataType& data);
-private:
+protected:
cache acache;
cache_bus upstream;
unsigned long replacements;
} stats;
+ cache_line_factory &line_factory;
unsigned line_size;
unsigned cache_size;
unsigned assoc;
// 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.
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;
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
}
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;
}
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
}
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);
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);
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
{
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*
// 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
// 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.
// 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;
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_line& accessed_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.
{
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.
// 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;
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;
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;
};
{
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.
// 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 ();