summaryrefslogtreecommitdiff
path: root/src/mem/ruby/system
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem/ruby/system')
-rw-r--r--src/mem/ruby/system/CacheMemory.cc483
-rw-r--r--src/mem/ruby/system/CacheMemory.hh465
-rw-r--r--src/mem/ruby/system/DirectoryMemory.cc11
-rw-r--r--src/mem/ruby/system/PersistentTable.cc204
-rw-r--r--src/mem/ruby/system/PersistentTable.hh102
-rw-r--r--src/mem/ruby/system/SConscript2
-rw-r--r--src/mem/ruby/system/Sequencer.hh2
-rw-r--r--src/mem/ruby/system/System.hh5
8 files changed, 811 insertions, 463 deletions
diff --git a/src/mem/ruby/system/CacheMemory.cc b/src/mem/ruby/system/CacheMemory.cc
new file mode 100644
index 000000000..cf3e094ad
--- /dev/null
+++ b/src/mem/ruby/system/CacheMemory.cc
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mem/ruby/system/CacheMemory.hh"
+
+int CacheMemory::m_num_last_level_caches = 0;
+MachineType CacheMemory::m_last_level_machine_type = MachineType_FIRST;
+
+// Output operator declaration
+//ostream& operator<<(ostream& out, const CacheMemory<ENTRY>& obj);
+
+// ******************* Definitions *******************
+
+// Output operator definition
+ostream& operator<<(ostream& out, const CacheMemory& obj)
+{
+ obj.print(out);
+ out << flush;
+ return out;
+}
+
+
+// ****************************************************************
+
+CacheMemory::CacheMemory(const string & name)
+ : m_cache_name(name)
+{
+ m_profiler_ptr = new CacheProfiler(name);
+}
+
+void CacheMemory::init(const vector<string> & argv)
+{
+ int cache_size = -1;
+ string policy;
+
+ m_num_last_level_caches =
+ MachineType_base_count(MachineType_FIRST);
+ m_controller = NULL;
+ for (uint32 i=0; i<argv.size(); i+=2) {
+ if (argv[i] == "size") {
+ cache_size = atoi(argv[i+1].c_str());
+ } else if (argv[i] == "latency") {
+ m_latency = atoi(argv[i+1].c_str());
+ } else if (argv[i] == "assoc") {
+ m_cache_assoc = atoi(argv[i+1].c_str());
+ } else if (argv[i] == "replacement_policy") {
+ policy = argv[i+1];
+ } else if (argv[i] == "controller") {
+ m_controller = RubySystem::getController(argv[i+1]);
+ if (m_last_level_machine_type < m_controller->getMachineType()) {
+ m_num_last_level_caches =
+ MachineType_base_count(m_controller->getMachineType());
+ m_last_level_machine_type =
+ m_controller->getMachineType();
+ }
+ } else {
+ cerr << "WARNING: CacheMemory: Unknown configuration parameter: " << argv[i] << endl;
+ }
+ }
+
+ int num_lines = cache_size/RubySystem::getBlockSizeBytes();
+ m_cache_num_sets = num_lines / m_cache_assoc;
+ m_cache_num_set_bits = log_int(m_cache_num_sets);
+ assert(m_cache_num_set_bits > 0);
+
+ if(policy == "PSEUDO_LRU")
+ m_replacementPolicy_ptr = new PseudoLRUPolicy(m_cache_num_sets, m_cache_assoc);
+ else if (policy == "LRU")
+ m_replacementPolicy_ptr = new LRUPolicy(m_cache_num_sets, m_cache_assoc);
+ else
+ assert(false);
+
+ m_cache.setSize(m_cache_num_sets);
+ m_locked.setSize(m_cache_num_sets);
+ for (int i = 0; i < m_cache_num_sets; i++) {
+ m_cache[i].setSize(m_cache_assoc);
+ m_locked[i].setSize(m_cache_assoc);
+ for (int j = 0; j < m_cache_assoc; j++) {
+ m_cache[i][j] = NULL;
+ m_locked[i][j] = -1;
+ }
+ }
+}
+
+CacheMemory::~CacheMemory()
+{
+ if(m_replacementPolicy_ptr != NULL)
+ delete m_replacementPolicy_ptr;
+ delete m_profiler_ptr;
+ for (int i = 0; i < m_cache_num_sets; i++) {
+ for (int j = 0; j < m_cache_assoc; j++) {
+ delete m_cache[i][j];
+ }
+ }
+}
+
+int
+CacheMemory::numberOfLastLevelCaches()
+{
+ return m_num_last_level_caches;
+}
+
+
+void CacheMemory::printConfig(ostream& out)
+{
+ out << "Cache config: " << m_cache_name << endl;
+ if (m_controller != NULL)
+ out << " controller: " << m_controller->getName() << endl;
+ out << " cache_associativity: " << m_cache_assoc << endl;
+ out << " num_cache_sets_bits: " << m_cache_num_set_bits << endl;
+ const int cache_num_sets = 1 << m_cache_num_set_bits;
+ out << " num_cache_sets: " << cache_num_sets << endl;
+ out << " cache_set_size_bytes: " << cache_num_sets * RubySystem::getBlockSizeBytes() << endl;
+ out << " cache_set_size_Kbytes: "
+ << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<10) << endl;
+ out << " cache_set_size_Mbytes: "
+ << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<20) << endl;
+ out << " cache_size_bytes: "
+ << cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc << endl;
+ out << " cache_size_Kbytes: "
+ << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<10) << endl;
+ out << " cache_size_Mbytes: "
+ << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<20) << endl;
+}
+
+// PRIVATE METHODS
+
+// convert a Address to its location in the cache
+Index CacheMemory::addressToCacheSet(const Address& address) const
+{
+ assert(address == line_address(address));
+ return address.bitSelect(RubySystem::getBlockSizeBits(), RubySystem::getBlockSizeBits() + m_cache_num_set_bits-1);
+}
+
+// Given a cache index: returns the index of the tag in a set.
+// returns -1 if the tag is not found.
+int CacheMemory::findTagInSet(Index cacheSet, const Address& tag) const
+{
+ assert(tag == line_address(tag));
+ // search the set for the tags
+ m5::hash_map<Address, int>::const_iterator it = m_tag_index.find(tag);
+ if (it != m_tag_index.end())
+ if (m_cache[cacheSet][it->second]->m_Permission != AccessPermission_NotPresent)
+ return it->second;
+ return -1; // Not found
+}
+
+// Given a cache index: returns the index of the tag in a set.
+// returns -1 if the tag is not found.
+int CacheMemory::findTagInSetIgnorePermissions(Index cacheSet, const Address& tag) const
+{
+ assert(tag == line_address(tag));
+ // search the set for the tags
+ m5::hash_map<Address, int>::const_iterator it = m_tag_index.find(tag);
+ if (it != m_tag_index.end())
+ return it->second;
+ return -1; // Not found
+}
+
+// PUBLIC METHODS
+bool CacheMemory::tryCacheAccess(const Address& address,
+ CacheRequestType type,
+ DataBlock*& data_ptr)
+{
+ assert(address == line_address(address));
+ DEBUG_EXPR(CACHE_COMP, HighPrio, address);
+ Index cacheSet = addressToCacheSet(address);
+ int loc = findTagInSet(cacheSet, address);
+ if(loc != -1){ // Do we even have a tag match?
+ AbstractCacheEntry* entry = m_cache[cacheSet][loc];
+ m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime());
+ data_ptr = &(entry->getDataBlk());
+
+ if(entry->m_Permission == AccessPermission_Read_Write) {
+ return true;
+ }
+ if ((entry->m_Permission == AccessPermission_Read_Only) &&
+ (type == CacheRequestType_LD || type == CacheRequestType_IFETCH)) {
+ return true;
+ }
+ // The line must not be accessible
+ }
+ data_ptr = NULL;
+ return false;
+}
+
+bool CacheMemory::testCacheAccess(const Address& address,
+ CacheRequestType type,
+ DataBlock*& data_ptr)
+{
+ assert(address == line_address(address));
+ DEBUG_EXPR(CACHE_COMP, HighPrio, address);
+ Index cacheSet = addressToCacheSet(address);
+ int loc = findTagInSet(cacheSet, address);
+ if(loc != -1){ // Do we even have a tag match?
+ AbstractCacheEntry* entry = m_cache[cacheSet][loc];
+ m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime());
+ data_ptr = &(entry->getDataBlk());
+
+ return (m_cache[cacheSet][loc]->m_Permission != AccessPermission_NotPresent);
+ }
+ data_ptr = NULL;
+ return false;
+}
+
+// tests to see if an address is present in the cache
+bool CacheMemory::isTagPresent(const Address& address) const
+{
+ assert(address == line_address(address));
+ Index cacheSet = addressToCacheSet(address);
+ int location = findTagInSet(cacheSet, address);
+
+ if (location == -1) {
+ // We didn't find the tag
+ DEBUG_EXPR(CACHE_COMP, LowPrio, address);
+ DEBUG_MSG(CACHE_COMP, LowPrio, "No tag match");
+ return false;
+ }
+ DEBUG_EXPR(CACHE_COMP, LowPrio, address);
+ DEBUG_MSG(CACHE_COMP, LowPrio, "found");
+ return true;
+}
+
+// Returns true if there is:
+// a) a tag match on this address or there is
+// b) an unused line in the same cache "way"
+bool CacheMemory::cacheAvail(const Address& address) const
+{
+ assert(address == line_address(address));
+
+ Index cacheSet = addressToCacheSet(address);
+
+ for (int i=0; i < m_cache_assoc; i++) {
+ AbstractCacheEntry* entry = m_cache[cacheSet][i];
+ if (entry != NULL) {
+ if (entry->m_Address == address || // Already in the cache
+ entry->m_Permission == AccessPermission_NotPresent) { // We found an empty entry
+ return true;
+ }
+ } else {
+ return true;
+ }
+ }
+ return false;
+}
+
+void CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry)
+{
+ assert(address == line_address(address));
+ assert(!isTagPresent(address));
+ assert(cacheAvail(address));
+ DEBUG_EXPR(CACHE_COMP, HighPrio, address);
+
+ // Find the first open slot
+ Index cacheSet = addressToCacheSet(address);
+ for (int i=0; i < m_cache_assoc; i++) {
+ if (m_cache[cacheSet][i] == NULL ||
+ m_cache[cacheSet][i]->m_Permission == AccessPermission_NotPresent) {
+ m_cache[cacheSet][i] = entry; // Init entry
+ m_cache[cacheSet][i]->m_Address = address;
+ m_cache[cacheSet][i]->m_Permission = AccessPermission_Invalid;
+ m_locked[cacheSet][i] = -1;
+ m_tag_index[address] = i;
+
+ m_replacementPolicy_ptr->touch(cacheSet, i, g_eventQueue_ptr->getTime());
+
+ return;
+ }
+ }
+ ERROR_MSG("Allocate didn't find an available entry");
+}
+
+void CacheMemory::deallocate(const Address& address)
+{
+ assert(address == line_address(address));
+ assert(isTagPresent(address));
+ DEBUG_EXPR(CACHE_COMP, HighPrio, address);
+ Index cacheSet = addressToCacheSet(address);
+ int location = findTagInSet(cacheSet, address);
+ if (location != -1){
+ delete m_cache[cacheSet][location];
+ m_cache[cacheSet][location] = NULL;
+ m_locked[cacheSet][location] = -1;
+ m_tag_index.erase(address);
+ }
+}
+
+// Returns with the physical address of the conflicting cache line
+Address CacheMemory::cacheProbe(const Address& address) const
+{
+ assert(address == line_address(address));
+ assert(!cacheAvail(address));
+
+ Index cacheSet = addressToCacheSet(address);
+ return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)]->m_Address;
+}
+
+// looks an address up in the cache
+AbstractCacheEntry& CacheMemory::lookup(const Address& address)
+{
+ assert(address == line_address(address));
+ Index cacheSet = addressToCacheSet(address);
+ int loc = findTagInSet(cacheSet, address);
+ assert(loc != -1);
+ return *m_cache[cacheSet][loc];
+}
+
+// looks an address up in the cache
+const AbstractCacheEntry& CacheMemory::lookup(const Address& address) const
+{
+ assert(address == line_address(address));
+ Index cacheSet = addressToCacheSet(address);
+ int loc = findTagInSet(cacheSet, address);
+ assert(loc != -1);
+ return *m_cache[cacheSet][loc];
+}
+
+AccessPermission CacheMemory::getPermission(const Address& address) const
+{
+ assert(address == line_address(address));
+ return lookup(address).m_Permission;
+}
+
+void CacheMemory::changePermission(const Address& address, AccessPermission new_perm)
+{
+ assert(address == line_address(address));
+ lookup(address).m_Permission = new_perm;
+ Index cacheSet = addressToCacheSet(address);
+ int loc = findTagInSet(cacheSet, address);
+ m_locked[cacheSet][loc] = -1;
+ assert(getPermission(address) == new_perm);
+}
+
+// Sets the most recently used bit for a cache block
+void CacheMemory::setMRU(const Address& address)
+{
+ Index cacheSet;
+
+ cacheSet = addressToCacheSet(address);
+ m_replacementPolicy_ptr->touch(cacheSet,
+ findTagInSet(cacheSet, address),
+ g_eventQueue_ptr->getTime());
+}
+
+void CacheMemory::profileMiss(const CacheMsg & msg)
+{
+ m_profiler_ptr->addStatSample(msg.getType(), msg.getAccessMode(),
+ msg.getSize(), msg.getPrefetch());
+}
+
+void CacheMemory::recordCacheContents(CacheRecorder& tr) const
+{
+ for (int i = 0; i < m_cache_num_sets; i++) {
+ for (int j = 0; j < m_cache_assoc; j++) {
+ AccessPermission perm = m_cache[i][j]->m_Permission;
+ CacheRequestType request_type = CacheRequestType_NULL;
+ if (perm == AccessPermission_Read_Only) {
+ if (m_is_instruction_only_cache) {
+ request_type = CacheRequestType_IFETCH;
+ } else {
+ request_type = CacheRequestType_LD;
+ }
+ } else if (perm == AccessPermission_Read_Write) {
+ request_type = CacheRequestType_ST;
+ }
+
+ if (request_type != CacheRequestType_NULL) {
+ // tr.addRecord(m_chip_ptr->getID(), m_cache[i][j].m_Address,
+ // Address(0), request_type, m_replacementPolicy_ptr->getLastAccess(i, j));
+ }
+ }
+ }
+}
+
+void CacheMemory::print(ostream& out) const
+{
+ out << "Cache dump: " << m_cache_name << endl;
+ for (int i = 0; i < m_cache_num_sets; i++) {
+ for (int j = 0; j < m_cache_assoc; j++) {
+ if (m_cache[i][j] != NULL) {
+ out << " Index: " << i
+ << " way: " << j
+ << " entry: " << *m_cache[i][j] << endl;
+ } else {
+ out << " Index: " << i
+ << " way: " << j
+ << " entry: NULL" << endl;
+ }
+ }
+ }
+}
+
+void CacheMemory::printData(ostream& out) const
+{
+ out << "printData() not supported" << endl;
+}
+
+void CacheMemory::clearStats() const
+{
+ m_profiler_ptr->clearStats();
+}
+
+void CacheMemory::printStats(ostream& out) const
+{
+ m_profiler_ptr->printStats(out);
+}
+
+void CacheMemory::getMemoryValue(const Address& addr, char* value,
+ unsigned int size_in_bytes ){
+ AbstractCacheEntry& entry = lookup(line_address(addr));
+ unsigned int startByte = addr.getAddress() - line_address(addr).getAddress();
+ for(unsigned int i=0; i<size_in_bytes; ++i){
+ value[i] = entry.getDataBlk().getByte(i + startByte);
+ }
+}
+
+void CacheMemory::setMemoryValue(const Address& addr, char* value,
+ unsigned int size_in_bytes ){
+ AbstractCacheEntry& entry = lookup(line_address(addr));
+ unsigned int startByte = addr.getAddress() - line_address(addr).getAddress();
+ assert(size_in_bytes > 0);
+ for(unsigned int i=0; i<size_in_bytes; ++i){
+ entry.getDataBlk().setByte(i + startByte, value[i]);
+ }
+
+ // entry = lookup(line_address(addr));
+}
+
+void
+CacheMemory::setLocked(const Address& address, int context)
+{
+ assert(address == line_address(address));
+ Index cacheSet = addressToCacheSet(address);
+ int loc = findTagInSet(cacheSet, address);
+ assert(loc != -1);
+ m_locked[cacheSet][loc] = context;
+}
+
+void
+CacheMemory::clearLocked(const Address& address)
+{
+ assert(address == line_address(address));
+ Index cacheSet = addressToCacheSet(address);
+ int loc = findTagInSet(cacheSet, address);
+ assert(loc != -1);
+ m_locked[cacheSet][loc] = -1;
+}
+
+bool
+CacheMemory::isLocked(const Address& address, int context)
+{
+ assert(address == line_address(address));
+ Index cacheSet = addressToCacheSet(address);
+ int loc = findTagInSet(cacheSet, address);
+ assert(loc != -1);
+ return m_locked[cacheSet][loc] == context;
+}
+
diff --git a/src/mem/ruby/system/CacheMemory.hh b/src/mem/ruby/system/CacheMemory.hh
index 7268189ea..8b84f33ec 100644
--- a/src/mem/ruby/system/CacheMemory.hh
+++ b/src/mem/ruby/system/CacheMemory.hh
@@ -54,6 +54,7 @@
#include "mem/ruby/slicc_interface/AbstractController.hh"
#include "mem/ruby/profiler/CacheProfiler.hh"
#include "mem/protocol/CacheMsg.hh"
+#include "base/hashmap.hh"
#include <vector>
class CacheMemory {
@@ -104,6 +105,8 @@ public:
AccessPermission getPermission(const Address& address) const;
void changePermission(const Address& address, AccessPermission new_perm);
+ static int numberOfLastLevelCaches();
+
int getLatency() const { return m_latency; }
// Hook for checkpointing the contents of the cache
@@ -169,465 +172,11 @@ private:
int m_cache_assoc;
static Vector< CacheMemory* > m_all_caches;
-};
+
+ static int m_num_last_level_caches;
+ static MachineType m_last_level_machine_type;
-// Output operator declaration
-//ostream& operator<<(ostream& out, const CacheMemory<ENTRY>& obj);
-
-// ******************* Definitions *******************
-
-// Output operator definition
-inline
-ostream& operator<<(ostream& out, const CacheMemory& obj)
-{
- obj.print(out);
- out << flush;
- return out;
-}
-
-
-// ****************************************************************
-
-inline
-CacheMemory::CacheMemory(const string & name)
- : m_cache_name(name)
-{
- m_profiler_ptr = new CacheProfiler(name);
-}
-
-inline
-void CacheMemory::init(const vector<string> & argv)
-{
- int cache_size = 0;
- string policy;
-
- m_controller = NULL;
- for (uint32 i=0; i<argv.size(); i+=2) {
- if (argv[i] == "size_kb") {
- cache_size = atoi(argv[i+1].c_str());
- } else if (argv[i] == "latency") {
- m_latency = atoi(argv[i+1].c_str());
- } else if (argv[i] == "assoc") {
- m_cache_assoc = atoi(argv[i+1].c_str());
- } else if (argv[i] == "replacement_policy") {
- policy = argv[i+1];
- } else if (argv[i] == "controller") {
- m_controller = RubySystem::getController(argv[i+1]);
- } else {
- cerr << "WARNING: CacheMemory: Unknown configuration parameter: " << argv[i] << endl;
- }
- }
-
- int num_lines = (cache_size*1024)/RubySystem::getBlockSizeBytes();
- m_cache_num_sets = num_lines / m_cache_assoc;
- m_cache_num_set_bits = log_int(m_cache_num_sets);
-
- if(policy == "PSEUDO_LRU")
- m_replacementPolicy_ptr = new PseudoLRUPolicy(m_cache_num_sets, m_cache_assoc);
- else if (policy == "LRU")
- m_replacementPolicy_ptr = new LRUPolicy(m_cache_num_sets, m_cache_assoc);
- else
- assert(false);
-
- m_cache.setSize(m_cache_num_sets);
- m_locked.setSize(m_cache_num_sets);
- for (int i = 0; i < m_cache_num_sets; i++) {
- m_cache[i].setSize(m_cache_assoc);
- m_locked[i].setSize(m_cache_assoc);
- for (int j = 0; j < m_cache_assoc; j++) {
- m_cache[i][j] = NULL;
- m_locked[i][j] = -1;
- }
- }
-}
-
-inline
-CacheMemory::~CacheMemory()
-{
- if(m_replacementPolicy_ptr != NULL)
- delete m_replacementPolicy_ptr;
-}
-
-inline
-void CacheMemory::printConfig(ostream& out)
-{
- out << "Cache config: " << m_cache_name << endl;
- if (m_controller != NULL)
- out << " controller: " << m_controller->getName() << endl;
- out << " cache_associativity: " << m_cache_assoc << endl;
- out << " num_cache_sets_bits: " << m_cache_num_set_bits << endl;
- const int cache_num_sets = 1 << m_cache_num_set_bits;
- out << " num_cache_sets: " << cache_num_sets << endl;
- out << " cache_set_size_bytes: " << cache_num_sets * RubySystem::getBlockSizeBytes() << endl;
- out << " cache_set_size_Kbytes: "
- << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<10) << endl;
- out << " cache_set_size_Mbytes: "
- << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<20) << endl;
- out << " cache_size_bytes: "
- << cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc << endl;
- out << " cache_size_Kbytes: "
- << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<10) << endl;
- out << " cache_size_Mbytes: "
- << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<20) << endl;
-}
-
-// PRIVATE METHODS
-
-// convert a Address to its location in the cache
-inline
-Index CacheMemory::addressToCacheSet(const Address& address) const
-{
- assert(address == line_address(address));
- return address.bitSelect(RubySystem::getBlockSizeBits(), RubySystem::getBlockSizeBits() + m_cache_num_set_bits-1);
-}
-
-// Given a cache index: returns the index of the tag in a set.
-// returns -1 if the tag is not found.
-inline
-int CacheMemory::findTagInSet(Index cacheSet, const Address& tag) const
-{
- assert(tag == line_address(tag));
- // search the set for the tags
- m5::hash_map<Address, int>::const_iterator it = m_tag_index.find(tag);
- if (it != m_tag_index.end())
- if (m_cache[cacheSet][it->second]->m_Permission != AccessPermission_NotPresent)
- return it->second;
- return -1; // Not found
-}
-
-// Given a cache index: returns the index of the tag in a set.
-// returns -1 if the tag is not found.
-inline
-int CacheMemory::findTagInSetIgnorePermissions(Index cacheSet, const Address& tag) const
-{
- assert(tag == line_address(tag));
- // search the set for the tags
- m5::hash_map<Address, int>::const_iterator it = m_tag_index.find(tag);
- if (it != m_tag_index.end())
- return it->second;
- return -1; // Not found
-}
-
-// PUBLIC METHODS
-inline
-bool CacheMemory::tryCacheAccess(const Address& address,
- CacheRequestType type,
- DataBlock*& data_ptr)
-{
- assert(address == line_address(address));
- DEBUG_EXPR(CACHE_COMP, HighPrio, address);
- Index cacheSet = addressToCacheSet(address);
- int loc = findTagInSet(cacheSet, address);
- if(loc != -1){ // Do we even have a tag match?
- AbstractCacheEntry* entry = m_cache[cacheSet][loc];
- m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime());
- data_ptr = &(entry->getDataBlk());
-
- if(entry->m_Permission == AccessPermission_Read_Write) {
- return true;
- }
- if ((entry->m_Permission == AccessPermission_Read_Only) &&
- (type == CacheRequestType_LD || type == CacheRequestType_IFETCH)) {
- return true;
- }
- // The line must not be accessible
- }
- data_ptr = NULL;
- return false;
-}
-
-inline
-bool CacheMemory::testCacheAccess(const Address& address,
- CacheRequestType type,
- DataBlock*& data_ptr)
-{
- assert(address == line_address(address));
- DEBUG_EXPR(CACHE_COMP, HighPrio, address);
- Index cacheSet = addressToCacheSet(address);
- int loc = findTagInSet(cacheSet, address);
- if(loc != -1){ // Do we even have a tag match?
- AbstractCacheEntry* entry = m_cache[cacheSet][loc];
- m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime());
- data_ptr = &(entry->getDataBlk());
-
- return (m_cache[cacheSet][loc]->m_Permission != AccessPermission_NotPresent);
- }
- data_ptr = NULL;
- return false;
-}
-
-// tests to see if an address is present in the cache
-inline
-bool CacheMemory::isTagPresent(const Address& address) const
-{
- assert(address == line_address(address));
- Index cacheSet = addressToCacheSet(address);
- int location = findTagInSet(cacheSet, address);
-
- if (location == -1) {
- // We didn't find the tag
- DEBUG_EXPR(CACHE_COMP, LowPrio, address);
- DEBUG_MSG(CACHE_COMP, LowPrio, "No tag match");
- return false;
- }
- DEBUG_EXPR(CACHE_COMP, LowPrio, address);
- DEBUG_MSG(CACHE_COMP, LowPrio, "found");
- return true;
-}
-
-// Returns true if there is:
-// a) a tag match on this address or there is
-// b) an unused line in the same cache "way"
-inline
-bool CacheMemory::cacheAvail(const Address& address) const
-{
- assert(address == line_address(address));
-
- Index cacheSet = addressToCacheSet(address);
-
- for (int i=0; i < m_cache_assoc; i++) {
- AbstractCacheEntry* entry = m_cache[cacheSet][i];
- if (entry != NULL) {
- if (entry->m_Address == address || // Already in the cache
- entry->m_Permission == AccessPermission_NotPresent) { // We found an empty entry
- return true;
- }
- } else {
- return true;
- }
- }
- return false;
-}
-
-inline
-void CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry)
-{
- assert(address == line_address(address));
- assert(!isTagPresent(address));
- assert(cacheAvail(address));
- DEBUG_EXPR(CACHE_COMP, HighPrio, address);
-
- // Find the first open slot
- Index cacheSet = addressToCacheSet(address);
- for (int i=0; i < m_cache_assoc; i++) {
- if (m_cache[cacheSet][i] == NULL ||
- m_cache[cacheSet][i]->m_Permission == AccessPermission_NotPresent) {
- m_cache[cacheSet][i] = entry; // Init entry
- m_cache[cacheSet][i]->m_Address = address;
- m_cache[cacheSet][i]->m_Permission = AccessPermission_Invalid;
- m_locked[cacheSet][i] = -1;
- m_tag_index[address] = i;
-
- m_replacementPolicy_ptr->touch(cacheSet, i, g_eventQueue_ptr->getTime());
-
- return;
- }
- }
- ERROR_MSG("Allocate didn't find an available entry");
-}
-
-inline
-void CacheMemory::deallocate(const Address& address)
-{
- assert(address == line_address(address));
- assert(isTagPresent(address));
- DEBUG_EXPR(CACHE_COMP, HighPrio, address);
- Index cacheSet = addressToCacheSet(address);
- int location = findTagInSet(cacheSet, address);
- if (location != -1){
- delete m_cache[cacheSet][location];
- m_cache[cacheSet][location] = NULL;
- m_locked[cacheSet][location] = -1;
- m_tag_index.erase(address);
- }
-}
-
-// Returns with the physical address of the conflicting cache line
-inline
-Address CacheMemory::cacheProbe(const Address& address) const
-{
- assert(address == line_address(address));
- assert(!cacheAvail(address));
-
- Index cacheSet = addressToCacheSet(address);
- return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)]->m_Address;
-}
-
-// looks an address up in the cache
-inline
-AbstractCacheEntry& CacheMemory::lookup(const Address& address)
-{
- assert(address == line_address(address));
- Index cacheSet = addressToCacheSet(address);
- int loc = findTagInSet(cacheSet, address);
- assert(loc != -1);
- return *m_cache[cacheSet][loc];
-}
-
-// looks an address up in the cache
-inline
-const AbstractCacheEntry& CacheMemory::lookup(const Address& address) const
-{
- assert(address == line_address(address));
- Index cacheSet = addressToCacheSet(address);
- int loc = findTagInSet(cacheSet, address);
- assert(loc != -1);
- return *m_cache[cacheSet][loc];
-}
-
-inline
-AccessPermission CacheMemory::getPermission(const Address& address) const
-{
- assert(address == line_address(address));
- return lookup(address).m_Permission;
-}
-
-inline
-void CacheMemory::changePermission(const Address& address, AccessPermission new_perm)
-{
- assert(address == line_address(address));
- lookup(address).m_Permission = new_perm;
- Index cacheSet = addressToCacheSet(address);
- int loc = findTagInSet(cacheSet, address);
- m_locked[cacheSet][loc] = -1;
- assert(getPermission(address) == new_perm);
-}
-
-// Sets the most recently used bit for a cache block
-inline
-void CacheMemory::setMRU(const Address& address)
-{
- Index cacheSet;
-
- cacheSet = addressToCacheSet(address);
- m_replacementPolicy_ptr->touch(cacheSet,
- findTagInSet(cacheSet, address),
- g_eventQueue_ptr->getTime());
-}
-
-inline
-void CacheMemory::profileMiss(const CacheMsg & msg)
-{
- m_profiler_ptr->addStatSample(msg.getType(), msg.getAccessMode(),
- msg.getSize(), msg.getPrefetch());
-}
-
-inline
-void CacheMemory::recordCacheContents(CacheRecorder& tr) const
-{
- for (int i = 0; i < m_cache_num_sets; i++) {
- for (int j = 0; j < m_cache_assoc; j++) {
- AccessPermission perm = m_cache[i][j]->m_Permission;
- CacheRequestType request_type = CacheRequestType_NULL;
- if (perm == AccessPermission_Read_Only) {
- if (m_is_instruction_only_cache) {
- request_type = CacheRequestType_IFETCH;
- } else {
- request_type = CacheRequestType_LD;
- }
- } else if (perm == AccessPermission_Read_Write) {
- request_type = CacheRequestType_ST;
- }
-
- if (request_type != CacheRequestType_NULL) {
- // tr.addRecord(m_chip_ptr->getID(), m_cache[i][j].m_Address,
- // Address(0), request_type, m_replacementPolicy_ptr->getLastAccess(i, j));
- }
- }
- }
-}
-
-inline
-void CacheMemory::print(ostream& out) const
-{
- out << "Cache dump: " << m_cache_name << endl;
- for (int i = 0; i < m_cache_num_sets; i++) {
- for (int j = 0; j < m_cache_assoc; j++) {
- if (m_cache[i][j] != NULL) {
- out << " Index: " << i
- << " way: " << j
- << " entry: " << *m_cache[i][j] << endl;
- } else {
- out << " Index: " << i
- << " way: " << j
- << " entry: NULL" << endl;
- }
- }
- }
-}
-
-inline
-void CacheMemory::printData(ostream& out) const
-{
- out << "printData() not supported" << endl;
-}
-
-inline void CacheMemory::clearStats() const
-{
- m_profiler_ptr->clearStats();
-}
-
-inline
-void CacheMemory::printStats(ostream& out) const
-{
- m_profiler_ptr->printStats(out);
-}
-
-inline
-void CacheMemory::getMemoryValue(const Address& addr, char* value,
- unsigned int size_in_bytes ){
- AbstractCacheEntry& entry = lookup(line_address(addr));
- unsigned int startByte = addr.getAddress() - line_address(addr).getAddress();
- for(unsigned int i=0; i<size_in_bytes; ++i){
- value[i] = entry.getDataBlk().getByte(i + startByte);
- }
-}
-
-inline
-void CacheMemory::setMemoryValue(const Address& addr, char* value,
- unsigned int size_in_bytes ){
- AbstractCacheEntry& entry = lookup(line_address(addr));
- unsigned int startByte = addr.getAddress() - line_address(addr).getAddress();
- assert(size_in_bytes > 0);
- for(unsigned int i=0; i<size_in_bytes; ++i){
- entry.getDataBlk().setByte(i + startByte, value[i]);
- }
-
- // entry = lookup(line_address(addr));
-}
-
-inline
-void
-CacheMemory::setLocked(const Address& address, int context)
-{
- assert(address == line_address(address));
- Index cacheSet = addressToCacheSet(address);
- int loc = findTagInSet(cacheSet, address);
- assert(loc != -1);
- m_locked[cacheSet][loc] = context;
-}
-
-inline
-void
-CacheMemory::clearLocked(const Address& address)
-{
- assert(address == line_address(address));
- Index cacheSet = addressToCacheSet(address);
- int loc = findTagInSet(cacheSet, address);
- assert(loc != -1);
- m_locked[cacheSet][loc] = -1;
-}
-
-inline
-bool
-CacheMemory::isLocked(const Address& address, int context)
-{
- assert(address == line_address(address));
- Index cacheSet = addressToCacheSet(address);
- int loc = findTagInSet(cacheSet, address);
- assert(loc != -1);
- return m_locked[cacheSet][loc] == context;
-}
+};
#endif //CACHEMEMORY_H
diff --git a/src/mem/ruby/system/DirectoryMemory.cc b/src/mem/ruby/system/DirectoryMemory.cc
index 46ebdbab4..9b2a3873c 100644
--- a/src/mem/ruby/system/DirectoryMemory.cc
+++ b/src/mem/ruby/system/DirectoryMemory.cc
@@ -84,11 +84,14 @@ void DirectoryMemory::init(const vector<string> & argv)
DirectoryMemory::~DirectoryMemory()
{
// free up all the directory entries
- for (int i=0;i<m_num_entries;i++)
- if (m_entries[i] != NULL)
- delete m_entries;
- if (m_entries != NULL)
+ for (uint64 i=0;i<m_num_entries;i++) {
+ if (m_entries[i] != NULL) {
+ delete m_entries[i];
+ }
+ }
+ if (m_entries != NULL) {
delete [] m_entries;
+ }
}
void DirectoryMemory::printConfig(ostream& out) const
diff --git a/src/mem/ruby/system/PersistentTable.cc b/src/mem/ruby/system/PersistentTable.cc
new file mode 100644
index 000000000..58b67ea60
--- /dev/null
+++ b/src/mem/ruby/system/PersistentTable.cc
@@ -0,0 +1,204 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "mem/ruby/system/PersistentTable.hh"
+#include "mem/gems_common/util.hh"
+
+// randomize so that handoffs are not locality-aware
+// int persistent_randomize[] = {0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15};
+// int persistent_randomize[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+
+
+PersistentTable::PersistentTable()
+{
+ m_map_ptr = new Map<Address, PersistentTableEntry>;
+}
+
+PersistentTable::~PersistentTable()
+{
+ delete m_map_ptr;
+ m_map_ptr = NULL;
+}
+
+void PersistentTable::persistentRequestLock(const Address& address,
+ MachineID locker,
+ AccessType type)
+{
+
+ // if (locker == m_chip_ptr->getID() )
+ // cout << "Chip " << m_chip_ptr->getID() << ": " << llocker
+ // << " requesting lock for " << address << endl;
+
+ // MachineID locker = (MachineID) persistent_randomize[llocker];
+
+ assert(address == line_address(address));
+ if (!m_map_ptr->exist(address)) {
+ // Allocate if not present
+ PersistentTableEntry entry;
+ entry.m_starving.add(locker);
+ if (type == AccessType_Write) {
+ entry.m_request_to_write.add(locker);
+ }
+ m_map_ptr->add(address, entry);
+ } else {
+ PersistentTableEntry& entry = m_map_ptr->lookup(address);
+
+ //
+ // Make sure we're not already in the locked set
+ //
+ assert(!(entry.m_starving.isElement(locker)));
+
+ entry.m_starving.add(locker);
+ if (type == AccessType_Write) {
+ entry.m_request_to_write.add(locker);
+ }
+ assert(entry.m_marked.isSubset(entry.m_starving));
+ }
+}
+
+void PersistentTable::persistentRequestUnlock(const Address& address,
+ MachineID unlocker)
+{
+ // if (unlocker == m_chip_ptr->getID() )
+ // cout << "Chip " << m_chip_ptr->getID() << ": " << uunlocker
+ // << " requesting unlock for " << address << endl;
+
+ // MachineID unlocker = (MachineID) persistent_randomize[uunlocker];
+
+ assert(address == line_address(address));
+ assert(m_map_ptr->exist(address));
+ PersistentTableEntry& entry = m_map_ptr->lookup(address);
+
+ //
+ // Make sure we're in the locked set
+ //
+ assert(entry.m_starving.isElement(unlocker));
+ assert(entry.m_marked.isSubset(entry.m_starving));
+ entry.m_starving.remove(unlocker);
+ entry.m_marked.remove(unlocker);
+ entry.m_request_to_write.remove(unlocker);
+ assert(entry.m_marked.isSubset(entry.m_starving));
+
+ // Deallocate if empty
+ if (entry.m_starving.isEmpty()) {
+ assert(entry.m_marked.isEmpty());
+ m_map_ptr->erase(address);
+ }
+}
+
+bool PersistentTable::okToIssueStarving(const Address& address,
+ MachineID machId) const
+{
+ assert(address == line_address(address));
+ if (!m_map_ptr->exist(address)) {
+ //
+ // No entry present
+ //
+ return true;
+ } else if (m_map_ptr->lookup(address).m_starving.isElement(machId)) {
+ //
+ // We can't issue another lockdown until are previous unlock has occurred
+ //
+ return false;
+ } else {
+ return (m_map_ptr->lookup(address).m_marked.isEmpty());
+ }
+}
+
+MachineID PersistentTable::findSmallest(const Address& address) const
+{
+ assert(address == line_address(address));
+ assert(m_map_ptr->exist(address));
+ const PersistentTableEntry& entry = m_map_ptr->lookup(address);
+ return entry.m_starving.smallestElement();
+}
+
+AccessType PersistentTable::typeOfSmallest(const Address& address) const
+{
+ assert(address == line_address(address));
+ assert(m_map_ptr->exist(address));
+ const PersistentTableEntry& entry = m_map_ptr->lookup(address);
+ if (entry.m_request_to_write.isElement(entry.m_starving.smallestElement())) {
+ return AccessType_Write;
+ } else {
+ return AccessType_Read;
+ }
+}
+
+void PersistentTable::markEntries(const Address& address)
+{
+ assert(address == line_address(address));
+ if (m_map_ptr->exist(address)) {
+ PersistentTableEntry& entry = m_map_ptr->lookup(address);
+
+ //
+ // None should be marked
+ //
+ assert(entry.m_marked.isEmpty());
+
+ //
+ // Mark all the nodes currently in the table
+ //
+ entry.m_marked = entry.m_starving;
+ }
+}
+
+bool PersistentTable::isLocked(const Address& address) const
+{
+ assert(address == line_address(address));
+ // If an entry is present, it must be locked
+ return (m_map_ptr->exist(address));
+}
+
+int PersistentTable::countStarvingForAddress(const Address& address) const
+{
+ if (m_map_ptr->exist(address)) {
+ PersistentTableEntry& entry = m_map_ptr->lookup(address);
+ return (entry.m_starving.count());
+ }
+ else {
+ return 0;
+ }
+}
+
+int PersistentTable::countReadStarvingForAddress(const Address& address) const
+{
+ if (m_map_ptr->exist(address)) {
+ PersistentTableEntry& entry = m_map_ptr->lookup(address);
+ return (entry.m_starving.count() - entry.m_request_to_write.count());
+ }
+ else {
+ return 0;
+ }
+}
+
+void PersistentTable::print(ostream& out) const
+{
+}
+
diff --git a/src/mem/ruby/system/PersistentTable.hh b/src/mem/ruby/system/PersistentTable.hh
new file mode 100644
index 000000000..8cbb48817
--- /dev/null
+++ b/src/mem/ruby/system/PersistentTable.hh
@@ -0,0 +1,102 @@
+
+/*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PersistentTable_H
+#define PersistentTable_H
+
+#include "mem/ruby/common/Global.hh"
+#include "mem/gems_common/Map.hh"
+#include "mem/ruby/common/Address.hh"
+#include "mem/ruby/system/MachineID.hh"
+#include "mem/protocol/AccessType.hh"
+#include "mem/ruby/common/NetDest.hh"
+
+class PersistentTableEntry {
+public:
+ void print(ostream& out) const {}
+
+ NetDest m_starving;
+ NetDest m_marked;
+ NetDest m_request_to_write;
+};
+
+class PersistentTable {
+public:
+ // Constructors
+ PersistentTable();
+
+ // Destructor
+ ~PersistentTable();
+
+ // Public Methods
+ void persistentRequestLock(const Address& address, MachineID locker, AccessType type);
+ void persistentRequestUnlock(const Address& address, MachineID unlocker);
+ bool okToIssueStarving(const Address& address, MachineID machID) const;
+ MachineID findSmallest(const Address& address) const;
+ AccessType typeOfSmallest(const Address& address) const;
+ void markEntries(const Address& address);
+ bool isLocked(const Address& addr) const;
+ int countStarvingForAddress(const Address& addr) const;
+ int countReadStarvingForAddress(const Address& addr) const;
+
+ static void printConfig(ostream& out) {}
+
+ void print(ostream& out) const;
+private:
+ // Private Methods
+
+ // Private copy constructor and assignment operator
+ PersistentTable(const PersistentTable& obj);
+ PersistentTable& operator=(const PersistentTable& obj);
+
+ // Data Members (m_prefix)
+ Map<Address, PersistentTableEntry>* m_map_ptr;
+};
+
+// ******************* Definitions *******************
+
+// Output operator definition
+extern inline
+ostream& operator<<(ostream& out, const PersistentTable& obj)
+{
+ obj.print(out);
+ out << flush;
+ return out;
+}
+
+// Output operator definition
+extern inline
+ostream& operator<<(ostream& out, const PersistentTableEntry& obj)
+{
+ obj.print(out);
+ out << flush;
+ return out;
+}
+
+#endif //PersistentTable_H
diff --git a/src/mem/ruby/system/SConscript b/src/mem/ruby/system/SConscript
index 1d8b1e2df..4ca1af114 100644
--- a/src/mem/ruby/system/SConscript
+++ b/src/mem/ruby/system/SConscript
@@ -35,8 +35,10 @@ if not env['RUBY']:
Source('DMASequencer.cc')
Source('DirectoryMemory.cc')
+Source('CacheMemory.cc')
Source('MemoryControl.cc')
Source('MemoryNode.cc')
+Source('PersistentTable.cc')
Source('RubyPort.cc')
Source('Sequencer.cc', Werror=False)
Source('System.cc')
diff --git a/src/mem/ruby/system/Sequencer.hh b/src/mem/ruby/system/Sequencer.hh
index 231df01bb..ce53dd8d7 100644
--- a/src/mem/ruby/system/Sequencer.hh
+++ b/src/mem/ruby/system/Sequencer.hh
@@ -63,6 +63,8 @@ struct SequencerRequest {
{}
};
+std::ostream& operator<<(std::ostream& out, const SequencerRequest& obj);
+
class Sequencer : public Consumer, public RubyPort {
public:
// Constructors
diff --git a/src/mem/ruby/system/System.hh b/src/mem/ruby/system/System.hh
index 38ef09177..1d36de878 100644
--- a/src/mem/ruby/system/System.hh
+++ b/src/mem/ruby/system/System.hh
@@ -107,7 +107,10 @@ public:
if (m_ports.count(name) != 1){
cerr << "Port " << name << " has " << m_ports.count(name) << " instances" << endl;
}
- assert(m_ports.count(name) == 1); m_ports[name]->registerHitCallback(hit_callback); return m_ports[name]; }
+ assert(m_ports.count(name) == 1);
+ m_ports[name]->registerHitCallback(hit_callback);
+ return m_ports[name];
+ }
static Network* getNetwork() { assert(m_network_ptr != NULL); return m_network_ptr; }
static Topology* getTopology(const string & name) { assert(m_topologies.count(name) == 1); return m_topologies[name]; }
static CacheMemory* getCache(const string & name) { assert(m_caches.count(name) == 1); return m_caches[name]; }