From: brolley Date: Thu, 29 Apr 2004 20:26:08 +0000 (+0000) Subject: 2004-04-29 Dave Brolley X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=57c047b9bd92959f991f01972163f09da254981c;p=pf3gnuchains%2Fpf3gnuchains3x.git 2004-04-29 Dave Brolley * cacheutil.cxx (cache_set::expell_line): Don't update the set here. 2004-04-29 Dave Brolley * 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 * 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. --- diff --git a/sid/component/cache/ChangeLog b/sid/component/cache/ChangeLog index 9e96e81bb8..aa9cf8c7b6 100644 --- a/sid/component/cache/ChangeLog +++ b/sid/component/cache/ChangeLog @@ -1,3 +1,75 @@ +2004-04-29 Dave Brolley + + * cacheutil.cxx (cache_set::expell_line): Don't update the set here. + +2004-04-29 Dave Brolley + + * 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 + + * 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 * log2.h: #undef log2, in case a macro collides with the function. diff --git a/sid/component/cache/cache.cxx b/sid/component/cache/cache.cxx index f8e6476c9c..d47f5c5432 100644 --- a/sid/component/cache/cache.cxx +++ b/sid/component/cache/cache.cxx @@ -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 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 () } } -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; } @@ -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 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; } diff --git a/sid/component/cache/cache.h b/sid/component/cache/cache.h index 13fb138dd9..ac50b54598 100644 --- a/sid/component/cache/cache.h +++ b/sid/component/cache/cache.h @@ -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 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); }; @@ -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 bus::status write_any (host_int_4 addr, DataType data); @@ -116,7 +117,7 @@ public: template 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; diff --git a/sid/component/cache/cacheutil.cxx b/sid/component/cache/cacheutil.cxx index 71e6317d61..9efcbffc09 100644 --- a/sid/component/cache/cacheutil.cxx +++ b/sid/component/cache/cacheutil.cxx @@ -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 (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 (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 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 diff --git a/sid/component/cache/cacheutil.h b/sid/component/cache/cacheutil.h index 40db5acf02..0e27a58585 100644 --- a/sid/component/cache/cacheutil.h +++ b/sid/component/cache/cacheutil.h @@ -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. @@ -17,24 +17,75 @@ 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 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 - 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 - 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_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. @@ -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 lines; + unsigned line_size; typedef std::vector ::iterator iterator_t; typedef std::vector ::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 ();