diff options
Diffstat (limited to 'src/mem/ruby/system')
27 files changed, 1693 insertions, 2831 deletions
diff --git a/src/mem/ruby/system/AbstractMemOrCache.hh b/src/mem/ruby/system/AbstractMemOrCache.hh index e56e1f505..641c117de 100644 --- a/src/mem/ruby/system/AbstractMemOrCache.hh +++ b/src/mem/ruby/system/AbstractMemOrCache.hh @@ -11,7 +11,6 @@ #define ABSTRACT_MEM_OR_CACHE_H #include "mem/ruby/common/Global.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" #include "mem/ruby/config/RubyConfig.hh" #include "mem/ruby/common/Address.hh" diff --git a/src/mem/ruby/system/CacheMemory.hh b/src/mem/ruby/system/CacheMemory.hh index 22799ab13..4d46ac908 100644 --- a/src/mem/ruby/system/CacheMemory.hh +++ b/src/mem/ruby/system/CacheMemory.hh @@ -38,13 +38,10 @@ #ifndef CACHEMEMORY_H #define CACHEMEMORY_H -#include "mem/ruby/slicc_interface/AbstractChip.hh" #include "mem/ruby/common/Global.hh" #include "mem/protocol/AccessPermission.hh" #include "mem/ruby/common/Address.hh" - -//dsm: PRUNED -//#include "mem/ruby/recorder/CacheRecorder.hh" +#include "mem/ruby/recorder/CacheRecorder.hh" #include "mem/protocol/CacheRequestType.hh" #include "mem/gems_common/Vector.hh" #include "mem/ruby/common/DataBlock.hh" @@ -52,18 +49,25 @@ #include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh" #include "mem/ruby/system/PseudoLRUPolicy.hh" #include "mem/ruby/system/LRUPolicy.hh" +#include "mem/ruby/slicc_interface/AbstractCacheEntry.hh" +#include "mem/ruby/system/System.hh" +#include "mem/ruby/slicc_interface/AbstractController.hh" #include <vector> -template<class ENTRY> class CacheMemory { public: // Constructors - CacheMemory(AbstractChip* chip_ptr, int numSetBits, int cacheAssoc, const MachineType machType, const string& description); + CacheMemory(const string & name); + void init(const vector<string> & argv); // Destructor ~CacheMemory(); + // factory + // static CacheMemory* createCache(int level, int num, char split_type, AbstractCacheEntry* (*entry_factory)()); + // static CacheMemory* getCache(int cache_id); + // Public Methods void printConfig(ostream& out); @@ -82,7 +86,7 @@ public: bool cacheAvail(const Address& address) const; // find an unused entry and sets the tag appropriate for the address - void allocate(const Address& address); + void allocate(const Address& address, AbstractCacheEntry* new_entry); // Explicitly free up this address void deallocate(const Address& address); @@ -91,16 +95,18 @@ public: Address cacheProbe(const Address& address) const; // looks an address up in the cache - ENTRY& lookup(const Address& address); - const ENTRY& lookup(const Address& address) const; + AbstractCacheEntry& lookup(const Address& address); + const AbstractCacheEntry& lookup(const Address& address) const; // Get/Set permission of cache block AccessPermission getPermission(const Address& address) const; void changePermission(const Address& address, AccessPermission new_perm); + int getLatency() const { return m_latency; } + // Hook for checkpointing the contents of the cache void recordCacheContents(CacheRecorder& tr) const; - void setAsInstructionCache(bool is_icache) { m_is_instruction_cache = is_icache; } + void setAsInstructionCache(bool is_icache) { m_is_instruction_only_cache = is_icache; } // Set this address to most recently used void setMRU(const Address& address); @@ -129,15 +135,18 @@ private: CacheMemory(const CacheMemory& obj); CacheMemory& operator=(const CacheMemory& obj); +private: + const string m_cache_name; + AbstractController* m_controller; + int m_latency; + // Data Members (m_prefix) - AbstractChip* m_chip_ptr; - MachineType m_machType; - string m_description; - bool m_is_instruction_cache; + bool m_is_instruction_only_cache; + bool m_is_data_only_cache; // The first index is the # of cache lines. // The second index is the the amount associativity. - Vector<Vector<ENTRY> > m_cache; + Vector<Vector<AbstractCacheEntry*> > m_cache; AbstractReplacementPolicy *m_replacementPolicy_ptr; @@ -145,18 +154,55 @@ private: int m_cache_num_set_bits; int m_cache_assoc; - bool is_locked; // for LL/SC + static Vector< CacheMemory* > m_all_caches; }; +/* +inline +CacheMemory* CacheMemory::getCache(int cache_id) +{ + assert(cache_id < RubyConfig::getNumberOfCaches()); + if (m_all_caches[cache_id] == NULL) { + cerr << "ERROR: Tried to obtain CacheMemory that hasn't been created yet." << endl; + assert(0); + } + return m_all_caches[cache_id]; +} +inline +CacheMemory* CacheMemory::createCache(int level, int num, char split_type_c, AbstractCacheEntry* (*entry_factory)()) +{ + string split_type; + switch(split_type_c) { + case 'i': + split_type = "instruction"; break; + case 'd': + split_type = "data"; break; + default: + split_type = "unified"; break; + } + int cache_id = RubyConfig::getCacheIDFromParams(level, num, split_type); + assert(cache_id < RubyConfig::getNumberOfCaches()); + if (m_all_caches.size() == 0) { + m_all_caches.setSize(RubyConfig::getNumberOfCaches()); + for (int i=0; i<m_all_caches.size(); i++) + m_all_caches[i] = NULL; + } + + string type = RubyConfig::getCacheType(cache_id); + if ( type == "SetAssociativeCache" ) { + m_all_caches[cache_id] = new CacheMemory(cache_id, entry_factory); + } + return m_all_caches[cache_id]; +} +*/ // Output operator declaration //ostream& operator<<(ostream& out, const CacheMemory<ENTRY>& obj); // ******************* Definitions ******************* // Output operator definition -template<class ENTRY> inline -ostream& operator<<(ostream& out, const CacheMemory<ENTRY>& obj) +ostream& operator<<(ostream& out, const CacheMemory& obj) { obj.print(out); out << flush; @@ -166,112 +212,142 @@ ostream& operator<<(ostream& out, const CacheMemory<ENTRY>& obj) // **************************************************************** -template<class ENTRY> inline -CacheMemory<ENTRY>::CacheMemory(AbstractChip* chip_ptr, int numSetBits, - int cacheAssoc, const MachineType machType, const string& description) +CacheMemory::CacheMemory(const string & name) + : m_cache_name(name) +{ +} +inline +void CacheMemory::init(const vector<string> & argv) { - //cout << "CacheMemory constructor numThreads = " << numThreads << endl; - m_chip_ptr = chip_ptr; - m_machType = machType; - m_description = MachineType_to_string(m_machType)+"_"+description; - m_cache_num_set_bits = numSetBits; - m_cache_num_sets = 1 << numSetBits; - m_cache_assoc = cacheAssoc; - m_is_instruction_cache = false; + 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; + } + } - m_cache.setSize(m_cache_num_sets); - if(strcmp(g_REPLACEMENT_POLICY, "PSEDUO_LRU") == 0) + m_cache_num_sets = cache_size / 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(strcmp(g_REPLACEMENT_POLICY, "LRU") == 0) + 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); for (int i = 0; i < m_cache_num_sets; i++) { m_cache[i].setSize(m_cache_assoc); for (int j = 0; j < m_cache_assoc; j++) { - m_cache[i][j].m_Address.setAddress(0); - m_cache[i][j].m_Permission = AccessPermission_NotPresent; + m_cache[i][j] = NULL; } } +} +/* +inline +CacheMemory::CacheMemory(int cache_id, AbstractCacheEntry* (*entry_factory)()) +{ + string split_type; + + m_cache_id = cache_id; + m_entry_factory = entry_factory; + + m_cache_num_set_bits = RubyConfig::getNumberOfCacheSetBits(cache_id); + m_cache_num_sets = RubyConfig::getNumberOfCacheSets(cache_id); + m_cache_assoc = RubyConfig::getCacheAssoc(cache_id); + split_type = RubyConfig::getCacheSplitType(cache_id); + m_is_instruction_only_cache = m_is_data_only_cache = false; + if (split_type == "instruction") + m_is_instruction_only_cache = true; + else if (split_type == "data") + m_is_data_only_cache = true; + else + assert(split_type == "unified"); + if(RubyConfig::getCacheReplacementPolicy(cache_id) == "PSEUDO_LRU") + m_replacementPolicy_ptr = new PseudoLRUPolicy(m_cache_num_sets, m_cache_assoc); + else if(RubyConfig::getCacheReplacementPolicy(cache_id) == "LRU") + m_replacementPolicy_ptr = new LRUPolicy(m_cache_num_sets, m_cache_assoc); + else + assert(false); - // cout << "Before setting trans address list size" << endl; - //create a trans address for each SMT thread -// m_trans_address_list.setSize(numThreads); -// for(ThreadID tid = 0; tid < numThreads; ++tid){ -// cout << "Setting list size for list " << tid << endl; -// m_trans_address_list[tid].setSize(30); -// } - //cout << "CacheMemory constructor finished" << endl; + m_cache.setSize(m_cache_num_sets); + for (int i = 0; i < m_cache_num_sets; i++) { + m_cache[i].setSize(m_cache_assoc); + for (int j = 0; j < m_cache_assoc; j++) { + m_cache[i][j] = m_entry_factory(); + } + } } - -template<class ENTRY> +*/ inline -CacheMemory<ENTRY>::~CacheMemory() +CacheMemory::~CacheMemory() { if(m_replacementPolicy_ptr != NULL) delete m_replacementPolicy_ptr; } -template<class ENTRY> inline -void CacheMemory<ENTRY>::printConfig(ostream& out) +void CacheMemory::printConfig(ostream& out) { - out << "Cache config: " << m_description << endl; + 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 * RubyConfig::dataBlockBytes() << endl; + out << " cache_set_size_bytes: " << cache_num_sets * RubySystem::getBlockSizeBytes() << endl; out << " cache_set_size_Kbytes: " - << double(cache_num_sets * RubyConfig::dataBlockBytes()) / (1<<10) << endl; + << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<10) << endl; out << " cache_set_size_Mbytes: " - << double(cache_num_sets * RubyConfig::dataBlockBytes()) / (1<<20) << endl; + << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<20) << endl; out << " cache_size_bytes: " - << cache_num_sets * RubyConfig::dataBlockBytes() * m_cache_assoc << endl; + << cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc << endl; out << " cache_size_Kbytes: " - << double(cache_num_sets * RubyConfig::dataBlockBytes() * m_cache_assoc) / (1<<10) << endl; + << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<10) << endl; out << " cache_size_Mbytes: " - << double(cache_num_sets * RubyConfig::dataBlockBytes() * m_cache_assoc) / (1<<20) << endl; + << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<20) << endl; } // PRIVATE METHODS // convert a Address to its location in the cache -template<class ENTRY> inline -Index CacheMemory<ENTRY>::addressToCacheSet(const Address& address) const +Index CacheMemory::addressToCacheSet(const Address& address) const { assert(address == line_address(address)); Index temp = -1; - switch (m_machType) { - case MACHINETYPE_L1CACHE_ENUM: - temp = map_address_to_L1CacheSet(address, m_cache_num_set_bits); - break; - case MACHINETYPE_L2CACHE_ENUM: - temp = map_address_to_L2CacheSet(address, m_cache_num_set_bits); - break; - default: - ERROR_MSG("Don't recognize m_machType"); - } - assert(temp < m_cache_num_sets); - assert(temp >= 0); - return temp; + 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. -template<class ENTRY> inline -int CacheMemory<ENTRY>::findTagInSet(Index cacheSet, const Address& tag) const +int CacheMemory::findTagInSet(Index cacheSet, const Address& tag) const { assert(tag == line_address(tag)); // search the set for the tags for (int i=0; i < m_cache_assoc; i++) { - if ((m_cache[cacheSet][i].m_Address == tag) && - (m_cache[cacheSet][i].m_Permission != AccessPermission_NotPresent)) { + if ((m_cache[cacheSet][i] != NULL) && + (m_cache[cacheSet][i]->m_Address == tag) && + (m_cache[cacheSet][i]->m_Permission != AccessPermission_NotPresent)) { return i; } } @@ -280,39 +356,37 @@ int CacheMemory<ENTRY>::findTagInSet(Index cacheSet, const Address& tag) const // Given a cache index: returns the index of the tag in a set. // returns -1 if the tag is not found. -template<class ENTRY> inline -int CacheMemory<ENTRY>::findTagInSetIgnorePermissions(Index cacheSet, const Address& tag) const +int CacheMemory::findTagInSetIgnorePermissions(Index cacheSet, const Address& tag) const { assert(tag == line_address(tag)); // search the set for the tags for (int i=0; i < m_cache_assoc; i++) { - if (m_cache[cacheSet][i].m_Address == tag) + if (m_cache[cacheSet][i] != NULL && m_cache[cacheSet][i]->m_Address == tag) return i; } return -1; // Not found } // PUBLIC METHODS -template<class ENTRY> inline -bool CacheMemory<ENTRY>::tryCacheAccess(const Address& address, - CacheRequestType type, - DataBlock*& data_ptr) +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? - ENTRY& entry = m_cache[cacheSet][loc]; + AbstractCacheEntry* entry = m_cache[cacheSet][loc]; m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime()); - data_ptr = &(entry.getDataBlk()); + data_ptr = &(entry->getDataBlk()); - if(entry.m_Permission == AccessPermission_Read_Write) { + if(entry->m_Permission == AccessPermission_Read_Write) { return true; } - if ((entry.m_Permission == AccessPermission_Read_Only) && + if ((entry->m_Permission == AccessPermission_Read_Only) && (type == CacheRequestType_LD || type == CacheRequestType_IFETCH)) { return true; } @@ -322,31 +396,29 @@ bool CacheMemory<ENTRY>::tryCacheAccess(const Address& address, return false; } -template<class ENTRY> inline -bool CacheMemory<ENTRY>::testCacheAccess(const Address& address, - CacheRequestType type, - DataBlock*& data_ptr) +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? - ENTRY& entry = m_cache[cacheSet][loc]; + AbstractCacheEntry* entry = m_cache[cacheSet][loc]; m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime()); - data_ptr = &(entry.getDataBlk()); + data_ptr = &(entry->getDataBlk()); - return (m_cache[cacheSet][loc].m_Permission != AccessPermission_NotPresent); + 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 -template<class ENTRY> inline -bool CacheMemory<ENTRY>::isTagPresent(const Address& address) const +bool CacheMemory::isTagPresent(const Address& address) const { assert(address == line_address(address)); Index cacheSet = addressToCacheSet(address); @@ -366,31 +438,29 @@ bool CacheMemory<ENTRY>::isTagPresent(const Address& address) const // Returns true if there is: // a) a tag match on this address or there is // b) an unused line in the same cache "way" -template<class ENTRY> inline -bool CacheMemory<ENTRY>::cacheAvail(const Address& address) const +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++) { - if (m_cache[cacheSet][i].m_Address == address) { - // Already in the cache - return true; - } - - if (m_cache[cacheSet][i].m_Permission == AccessPermission_NotPresent) { - // We found an empty entry + 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; } -template<class ENTRY> inline -void CacheMemory<ENTRY>::allocate(const Address& address) +void CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry) { assert(address == line_address(address)); assert(!isTagPresent(address)); @@ -400,10 +470,11 @@ void CacheMemory<ENTRY>::allocate(const Address& address) // Find the first open slot Index cacheSet = addressToCacheSet(address); for (int i=0; i < m_cache_assoc; i++) { - if (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; + 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_replacementPolicy_ptr->touch(cacheSet, i, g_eventQueue_ptr->getTime()); @@ -413,63 +484,62 @@ void CacheMemory<ENTRY>::allocate(const Address& address) ERROR_MSG("Allocate didn't find an available entry"); } -template<class ENTRY> inline -void CacheMemory<ENTRY>::deallocate(const Address& address) +void CacheMemory::deallocate(const Address& address) { assert(address == line_address(address)); assert(isTagPresent(address)); DEBUG_EXPR(CACHE_COMP, HighPrio, address); - lookup(address).m_Permission = AccessPermission_NotPresent; + Index cacheSet = addressToCacheSet(address); + int location = findTagInSet(cacheSet, address); + if (location != -1){ + delete m_cache[cacheSet][location]; + m_cache[cacheSet][location] = NULL; + } } // Returns with the physical address of the conflicting cache line -template<class ENTRY> inline -Address CacheMemory<ENTRY>::cacheProbe(const Address& address) const +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; + return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)]->m_Address; } // looks an address up in the cache -template<class ENTRY> inline -ENTRY& CacheMemory<ENTRY>::lookup(const Address& address) +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]; + return *m_cache[cacheSet][loc]; } // looks an address up in the cache -template<class ENTRY> inline -const ENTRY& CacheMemory<ENTRY>::lookup(const Address& address) const +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]; + return *m_cache[cacheSet][loc]; } -template<class ENTRY> inline -AccessPermission CacheMemory<ENTRY>::getPermission(const Address& address) const +AccessPermission CacheMemory::getPermission(const Address& address) const { assert(address == line_address(address)); return lookup(address).m_Permission; } -template<class ENTRY> inline -void CacheMemory<ENTRY>::changePermission(const Address& address, AccessPermission new_perm) +void CacheMemory::changePermission(const Address& address, AccessPermission new_perm) { assert(address == line_address(address)); lookup(address).m_Permission = new_perm; @@ -477,9 +547,8 @@ void CacheMemory<ENTRY>::changePermission(const Address& address, AccessPermissi } // Sets the most recently used bit for a cache block -template<class ENTRY> inline -void CacheMemory<ENTRY>::setMRU(const Address& address) +void CacheMemory::setMRU(const Address& address) { Index cacheSet; @@ -489,19 +558,15 @@ void CacheMemory<ENTRY>::setMRU(const Address& address) g_eventQueue_ptr->getTime()); } -template<class ENTRY> inline -void CacheMemory<ENTRY>::recordCacheContents(CacheRecorder& tr) const +void CacheMemory::recordCacheContents(CacheRecorder& tr) const { -//dsm: Uses CacheRecorder, PRUNED -assert(false); - -/* for (int i = 0; i < m_cache_num_sets; i++) { + 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; + AccessPermission perm = m_cache[i][j]->m_Permission; CacheRequestType request_type = CacheRequestType_NULL; if (perm == AccessPermission_Read_Only) { - if (m_is_instruction_cache) { + if (m_is_instruction_only_cache) { request_type = CacheRequestType_IFETCH; } else { request_type = CacheRequestType_LD; @@ -511,55 +576,59 @@ assert(false); } 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)); + // tr.addRecord(m_chip_ptr->getID(), m_cache[i][j].m_Address, + // Address(0), request_type, m_replacementPolicy_ptr->getLastAccess(i, j)); } } - }*/ + } } -template<class ENTRY> inline -void CacheMemory<ENTRY>::print(ostream& out) const +void CacheMemory::print(ostream& out) const { - out << "Cache dump: " << m_description << endl; + 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++) { - out << " Index: " << i - << " way: " << j - << " entry: " << m_cache[i][j] << endl; + 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; + } } } } -template<class ENTRY> inline -void CacheMemory<ENTRY>::printData(ostream& out) const +void CacheMemory::printData(ostream& out) const { out << "printData() not supported" << endl; } -template<class ENTRY> -void CacheMemory<ENTRY>::getMemoryValue(const Address& addr, char* value, - unsigned int size_in_bytes ){ - ENTRY entry = lookup(line_address(addr)); +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.m_DataBlk.getByte(i + startByte); + value[i] = entry.getDataBlk().getByte(i + startByte); } } -template<class ENTRY> -void CacheMemory<ENTRY>::setMemoryValue(const Address& addr, char* value, - unsigned int size_in_bytes ){ - ENTRY& entry = lookup(line_address(addr)); +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.m_DataBlk.setByte(i + startByte, value[i]); + entry.getDataBlk().setByte(i + startByte, value[i]); } - entry = lookup(line_address(addr)); + // entry = lookup(line_address(addr)); } #endif //CACHEMEMORY_H diff --git a/src/mem/ruby/system/DMASequencer.cc b/src/mem/ruby/system/DMASequencer.cc new file mode 100644 index 000000000..4aa092113 --- /dev/null +++ b/src/mem/ruby/system/DMASequencer.cc @@ -0,0 +1,130 @@ + +#include "mem/ruby/system/DMASequencer.hh" +#include "mem/ruby/buffers/MessageBuffer.hh" +#include "mem/ruby/slicc_interface/AbstractController.hh" + +/* SLICC generated types */ +#include "mem/protocol/DMARequestMsg.hh" +#include "mem/protocol/DMARequestType.hh" +#include "mem/protocol/DMAResponseMsg.hh" +#include "mem/ruby/system/System.hh" + +DMASequencer::DMASequencer(const string & name) + : RubyPort(name) +{ +} + +void DMASequencer::init(const vector<string> & argv) +{ + m_version = -1; + m_controller = NULL; + for (size_t i=0;i<argv.size();i+=2) { + if (argv[i] == "controller") + m_controller = RubySystem::getController(argv[i+1]); + else if (argv[i] == "version") + m_version = atoi(argv[i+1].c_str()); + } + assert(m_controller != NULL); + assert(m_version != -1); + + m_mandatory_q_ptr = m_controller->getMandatoryQueue(); + m_is_busy = false; +} + +int64_t DMASequencer::makeRequest(const RubyRequest & request) +{ + uint64_t paddr = request.paddr; + uint8_t* data = request.data; + int len = request.len; + bool write = false; + switch(request.type) { + case RubyRequestType_LD: + write = false; + break; + case RubyRequestType_ST: + write = true; + break; + case RubyRequestType_NULL: + case RubyRequestType_IFETCH: + case RubyRequestType_RMW: + assert(0); + } + + assert(!m_is_busy); + m_is_busy = true; + + active_request.start_paddr = paddr; + active_request.write = write; + active_request.data = data; + active_request.len = len; + active_request.bytes_completed = 0; + active_request.bytes_issued = 0; + active_request.id = makeUniqueRequestID(); + + DMARequestMsg msg; + msg.getPhysicalAddress() = Address(paddr); + msg.getType() = write ? DMARequestType_WRITE : DMARequestType_READ; + msg.getOffset() = paddr & RubyConfig::dataBlockMask(); + msg.getLen() = (msg.getOffset() + len) < RubySystem::getBlockSizeBytes() ? + (msg.getOffset() + len) : + RubySystem::getBlockSizeBytes() - msg.getOffset(); + if (write) { + msg.getType() = DMARequestType_WRITE; + msg.getDataBlk().setData(data, 0, msg.getLen()); + } else { + msg.getType() = DMARequestType_READ; + } + m_mandatory_q_ptr->enqueue(msg); + active_request.bytes_issued += msg.getLen(); + + return active_request.id; +} + +void DMASequencer::issueNext() +{ + assert(m_is_busy == true); + active_request.bytes_completed = active_request.bytes_issued; + if (active_request.len == active_request.bytes_completed) { + m_hit_callback(active_request.id); + m_is_busy = false; + return; + } + + DMARequestMsg msg; + msg.getPhysicalAddress() = Address(active_request.start_paddr + active_request.bytes_completed); + assert((msg.getPhysicalAddress().getAddress() & RubyConfig::dataBlockMask()) == 0); + msg.getOffset() = 0; + msg.getType() = active_request.write ? DMARequestType_WRITE : DMARequestType_READ; + msg.getLen() = active_request.len - active_request.bytes_completed < RubySystem::getBlockSizeBytes() ? + active_request.len - active_request.bytes_completed : + RubySystem::getBlockSizeBytes(); + if (active_request.write) { + msg.getDataBlk().setData(&active_request.data[active_request.bytes_completed], 0, msg.getLen()); + msg.getType() = DMARequestType_WRITE; + } else { + msg.getType() = DMARequestType_READ; + } + m_mandatory_q_ptr->enqueue(msg); + active_request.bytes_issued += msg.getLen(); +} + +void DMASequencer::dataCallback(const DataBlock & dblk) +{ + assert(m_is_busy == true); + int len = active_request.bytes_issued - active_request.bytes_completed; + int offset = 0; + if (active_request.bytes_completed == 0) + offset = active_request.start_paddr & RubyConfig::dataBlockMask(); + memcpy(&active_request.data[active_request.bytes_completed], dblk.getData(offset, len), len); + issueNext(); +} + +void DMASequencer::ackCallback() +{ + issueNext(); +} + +void DMASequencer::printConfig(ostream & out) +{ + +} diff --git a/src/mem/ruby/system/DMASequencer.hh b/src/mem/ruby/system/DMASequencer.hh new file mode 100644 index 000000000..2665549e3 --- /dev/null +++ b/src/mem/ruby/system/DMASequencer.hh @@ -0,0 +1,49 @@ + +#ifndef DMASEQUENCER_H +#define DMASEQUENCER_H + +#include <ostream> +#include "mem/ruby/common/DataBlock.hh" +#include "mem/ruby/system/RubyPort.hh" + +struct DMARequest { + uint64_t start_paddr; + int len; + bool write; + int bytes_completed; + int bytes_issued; + uint8* data; + int64_t id; +}; + +class MessageBuffer; +class AbstractController; + +class DMASequencer :public RubyPort { +public: + DMASequencer(const string & name); + void init(const vector<string> & argv); + /* external interface */ + int64_t makeRequest(const RubyRequest & request); + // void issueRequest(uint64_t paddr, uint8* data, int len, bool rw); + bool busy() { return m_is_busy;} + + /* SLICC callback */ + void dataCallback(const DataBlock & dblk); + void ackCallback(); + + void printConfig(std::ostream & out); + +private: + void issueNext(); + +private: + int m_version; + AbstractController* m_controller; + bool m_is_busy; + DMARequest active_request; + int num_active_requests; + MessageBuffer* m_mandatory_q_ptr; +}; + +#endif // DMACONTROLLER_H diff --git a/src/mem/ruby/system/DirectoryMemory.cc b/src/mem/ruby/system/DirectoryMemory.cc index 40b990e2d..294d57de2 100644 --- a/src/mem/ruby/system/DirectoryMemory.cc +++ b/src/mem/ruby/system/DirectoryMemory.cc @@ -37,118 +37,150 @@ */ #include "mem/ruby/system/System.hh" -#include "mem/ruby/common/Driver.hh" #include "mem/ruby/system/DirectoryMemory.hh" #include "mem/ruby/slicc_interface/RubySlicc_Util.hh" #include "mem/ruby/config/RubyConfig.hh" -#include "mem/protocol/Chip.hh" +#include "mem/ruby/slicc_interface/AbstractController.hh" +#include "mem/gems_common/util.hh" -DirectoryMemory::DirectoryMemory(Chip* chip_ptr, int version) +int DirectoryMemory::m_num_directories = 0; +int DirectoryMemory::m_num_directories_bits = 0; +int DirectoryMemory::m_total_size_bytes = 0; + +DirectoryMemory::DirectoryMemory(const string & name) + : m_name(name) { - m_chip_ptr = chip_ptr; - m_version = version; - // THIS DOESN'T SEEM TO WORK -- MRM - // m_size = RubyConfig::memoryModuleBlocks()/RubyConfig::numberOfDirectory(); - m_size = RubyConfig::memoryModuleBlocks(); - assert(m_size > 0); - /********************************************************************* - // allocates an array of directory entry pointers & sets them to NULL - m_entries = new Directory_Entry*[m_size]; - if (m_entries == NULL) { - ERROR_MSG("Directory Memory: unable to allocate memory."); +} + +void DirectoryMemory::init(const vector<string> & argv) +{ + m_controller = NULL; + for (vector<string>::const_iterator it = argv.begin(); it != argv.end(); it++) { + if ( (*it) == "version" ) + m_version = atoi( (*(++it)).c_str() ); + else if ( (*it) == "size_mb" ) { + m_size_bytes = atoi((*(++it)).c_str()) * (1<<20); + m_size_bits = log_int(m_size_bytes); + } else if ( (*it) == "controller" ) { + m_controller = RubySystem::getController((*(++it))); + } else + assert(0); } + assert(m_controller != NULL); - for (int i=0; i < m_size; i++) { + m_num_entries = m_size_bytes / RubySystem::getBlockSizeBytes(); + m_entries = new Directory_Entry*[m_num_entries]; + for (int i=0; i < m_num_entries; i++) m_entries[i] = NULL; - } - *///////////////////////////////////////////////////////////////////// + + m_ram = g_system_ptr->getMemoryVector(); + + m_num_directories++; + m_num_directories_bits = log_int(m_num_directories); + m_total_size_bytes += m_size_bytes; } DirectoryMemory::~DirectoryMemory() { - /********************************************************************* // free up all the directory entries - for (int i=0; i < m_size; i++) { - if (m_entries[i] != NULL) { - delete m_entries[i]; - m_entries[i] = NULL; - } - } + for (int i=0;i<m_num_entries;i++) + if (m_entries[i] != NULL) + delete m_entries; + if (m_entries != NULL) + delete [] m_entries; +} - // free up the array of directory entries - delete[] m_entries; - *////////////////////////////////////////////////////////////////////// - m_entries.clear(); +void DirectoryMemory::printConfig(ostream& out) const +{ + out << "DirectoryMemory module config: " << m_name << endl; + out << " controller: " << m_controller->getName() << endl; + out << " version: " << m_version << endl; + out << " memory_bits: " << m_size_bits << endl; + out << " memory_size_bytes: " << m_size_bytes << endl; + out << " memory_size_Kbytes: " << double(m_size_bytes) / (1<<10) << endl; + out << " memory_size_Mbytes: " << double(m_size_bytes) / (1<<20) << endl; + out << " memory_size_Gbytes: " << double(m_size_bytes) / (1<<30) << endl; } // Static method -void DirectoryMemory::printConfig(ostream& out) +void DirectoryMemory::printGlobalConfig(ostream & out) +{ + out << "DirectoryMemory Global Config: " << endl; + out << " number of directory memories: " << m_num_directories << endl; + if (m_num_directories > 1) { + out << " number of selection bits: " << m_num_directories_bits << endl; + out << " selection bits: " << RubySystem::getBlockSizeBits()+m_num_directories_bits-1 + << "-" << RubySystem::getBlockSizeBits() << endl; + } + out << " total memory size bytes: " << m_total_size_bytes << endl; + out << " total memory size bits: " << log_int(m_total_size_bytes) << endl; + +} + +int DirectoryMemory::mapAddressToDirectoryVersion(PhysAddress address) { - out << "Memory config:" << endl; - out << " memory_bits: " << RubyConfig::memorySizeBits() << endl; - out << " memory_size_bytes: " << RubyConfig::memorySizeBytes() << endl; - out << " memory_size_Kbytes: " << double(RubyConfig::memorySizeBytes()) / (1<<10) << endl; - out << " memory_size_Mbytes: " << double(RubyConfig::memorySizeBytes()) / (1<<20) << endl; - out << " memory_size_Gbytes: " << double(RubyConfig::memorySizeBytes()) / (1<<30) << endl; - - out << " module_bits: " << RubyConfig::memoryModuleBits() << endl; - out << " module_size_lines: " << RubyConfig::memoryModuleBlocks() << endl; - out << " module_size_bytes: " << RubyConfig::memoryModuleBlocks() * RubyConfig::dataBlockBytes() << endl; - out << " module_size_Kbytes: " << double(RubyConfig::memoryModuleBlocks() * RubyConfig::dataBlockBytes()) / (1<<10) << endl; - out << " module_size_Mbytes: " << double(RubyConfig::memoryModuleBlocks() * RubyConfig::dataBlockBytes()) / (1<<20) << endl; + if (m_num_directories_bits == 0) return 0; + int ret = address.bitSelect(RubySystem::getBlockSizeBits(), + RubySystem::getBlockSizeBits()+m_num_directories_bits-1); + return ret; } // Public method bool DirectoryMemory::isPresent(PhysAddress address) { - return (map_Address_to_DirectoryNode(address) == m_chip_ptr->getID()*RubyConfig::numberOfDirectoryPerChip()+m_version); + bool ret = (mapAddressToDirectoryVersion(address) == m_version); + return ret; } -void DirectoryMemory::readPhysMem(uint64 address, int size, void * data) +int DirectoryMemory::mapAddressToLocalIdx(PhysAddress address) { + int ret = address.getAddress() >> (RubySystem::getBlockSizeBits() + m_num_directories_bits); + return ret; } Directory_Entry& DirectoryMemory::lookup(PhysAddress address) { assert(isPresent(address)); + Directory_Entry* entry; + int idx = mapAddressToLocalIdx(address); + entry = m_entries[idx]; + if (entry == NULL) { + entry = new Directory_Entry; + entry->getDataBlk().assign(m_ram->getBlockPtr(address)); + m_entries[idx] = entry; + } + return (*entry); +} +/* +Directory_Entry& DirectoryMemory::lookup(PhysAddress address) +{ + assert(isPresent(address)); Index index = address.memoryModuleIndex(); if (index < 0 || index > m_size) { - WARN_EXPR(m_chip_ptr->getID()); WARN_EXPR(address.getAddress()); WARN_EXPR(index); WARN_EXPR(m_size); ERROR_MSG("Directory Memory Assertion: accessing memory out of range."); } - - map<Index, Directory_Entry*>::iterator iter = m_entries.find(index); - Directory_Entry* entry = m_entries.find(index)->second; + Directory_Entry* entry = m_entries[index]; // allocate the directory entry on demand. - if (iter == m_entries.end()) { + if (entry == NULL) { entry = new Directory_Entry; + entry->getDataBlk().assign(m_ram->getBlockPtr(address)); - // entry->getProcOwner() = m_chip_ptr->getID(); // FIXME - This should not be hard coded - // entry->getDirOwner() = true; // FIXME - This should not be hard-coded - - // load the data from physicalMemory when first initalizing - physical_address_t physAddr = address.getAddress(); - int8 * dataArray = (int8 * )malloc(RubyConfig::dataBlockBytes() * sizeof(int8)); - readPhysMem(physAddr, RubyConfig::dataBlockBytes(), dataArray); - - for(int j=0; j < RubyConfig::dataBlockBytes(); j++) { - entry->getDataBlk().setByte(j, dataArray[j]); - } - DEBUG_EXPR(NODE_COMP, MedPrio,entry->getDataBlk()); // store entry to the table - m_entries.insert(make_pair(index, entry)); + m_entries[index] = entry; } + return (*entry); } +*/ -/* void DirectoryMemory::invalidateBlock(PhysAddress address) { + /* assert(isPresent(address)); Index index = address.memoryModuleIndex(); @@ -161,16 +193,11 @@ void DirectoryMemory::invalidateBlock(PhysAddress address) delete m_entries[index]; m_entries[index] = NULL; } - + */ } -*/ void DirectoryMemory::print(ostream& out) const { - out << "Directory dump: " << endl; - for(map<Index, Directory_Entry*>::const_iterator it = m_entries.begin(); it != m_entries.end(); ++it) { - out << it->first << ": "; - out << *(it->second) << endl; - } + } diff --git a/src/mem/ruby/system/DirectoryMemory.hh b/src/mem/ruby/system/DirectoryMemory.hh index 6451ed459..6445ecc62 100644 --- a/src/mem/ruby/system/DirectoryMemory.hh +++ b/src/mem/ruby/system/DirectoryMemory.hh @@ -41,26 +41,34 @@ #include "mem/ruby/common/Global.hh" #include "mem/ruby/common/Address.hh" +#include "mem/ruby/system/MemoryVector.hh" #include "mem/protocol/Directory_Entry.hh" -#include <map> -class Chip; +class AbstractController; class DirectoryMemory { public: // Constructors - DirectoryMemory(Chip* chip_ptr, int version); + DirectoryMemory(const string & name); + void init(const vector<string> & argv); + // DirectoryMemory(int version); // Destructor ~DirectoryMemory(); + int mapAddressToLocalIdx(PhysAddress address); + static int mapAddressToDirectoryVersion(PhysAddress address); + + int getSize() { return m_size_bytes; } + // Public Methods - static void printConfig(ostream& out); + void printConfig(ostream& out) const; + static void printGlobalConfig(ostream & out); bool isPresent(PhysAddress address); - // dummy function - void readPhysMem(uint64 address, int size, void * data); Directory_Entry& lookup(PhysAddress address); + void invalidateBlock(PhysAddress address); + void print(ostream& out) const; private: @@ -70,11 +78,22 @@ private: DirectoryMemory(const DirectoryMemory& obj); DirectoryMemory& operator=(const DirectoryMemory& obj); +private: + const string m_name; + AbstractController* m_controller; // Data Members (m_ prefix) - map<Index, Directory_Entry*> m_entries; - Chip* m_chip_ptr; - int m_size; // # of memory module blocks for this directory + Directory_Entry **m_entries; + // int m_size; // # of memory module blocks this directory is responsible for + uint32 m_size_bytes; + uint32 m_size_bits; + int m_num_entries; int m_version; + + static int m_num_directories; + static int m_num_directories_bits; + static int m_total_size_bytes; + + MemoryVector* m_ram; }; // Output operator declaration diff --git a/src/mem/ruby/system/MemoryControl.cc b/src/mem/ruby/system/MemoryControl.cc index 86c6526c8..f9159ed3e 100644 --- a/src/mem/ruby/system/MemoryControl.cc +++ b/src/mem/ruby/system/MemoryControl.cc @@ -110,21 +110,21 @@ * */ -#include <list> - -#include "base/cprintf.hh" #include "mem/ruby/common/Global.hh" #include "mem/gems_common/Map.hh" #include "mem/ruby/common/Address.hh" #include "mem/ruby/profiler/Profiler.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" #include "mem/ruby/system/System.hh" #include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh" #include "mem/ruby/slicc_interface/NetworkMessage.hh" #include "mem/ruby/network/Network.hh" + #include "mem/ruby/common/Consumer.hh" + #include "mem/ruby/system/MemoryControl.hh" +#include <list> + class Consumer; // Value to reset watchdog timer to. @@ -151,32 +151,66 @@ ostream& operator<<(ostream& out, const MemoryControl& obj) // **************************************************************** // CONSTRUCTOR +MemoryControl::MemoryControl(const string & name) + : m_name(name) +{ + m_name = name; +// printf ("MemoryControl name is %s \n", m_name.c_str()); +} + +void MemoryControl::init(const vector<string> & argv) +{ + + for (vector<string>::const_iterator it = argv.begin(); it != argv.end(); it++) { + if ( (*it) == "version" ) + m_version = atoi( (*(++it)).c_str() ); + else if ( (*it) == "mem_bus_cycle_multiplier" ) { + m_mem_bus_cycle_multiplier = atoi((*(++it)).c_str()); + } else if ( (*it) == "banks_per_rank" ) { + m_banks_per_rank = atoi((*(++it)).c_str()); + } else if ( (*it) == "ranks_per_dimm" ) { + m_ranks_per_dimm = atoi((*(++it)).c_str()); + } else if ( (*it) == "dimms_per_channel" ) { + m_dimms_per_channel = atoi((*(++it)).c_str()); + } else if ( (*it) == "bank_bit_0" ) { + m_bank_bit_0 = atoi((*(++it)).c_str()); + } else if ( (*it) == "rank_bit_0" ) { + m_rank_bit_0 = atoi((*(++it)).c_str()); + } else if ( (*it) == "dimm_bit_0" ) { + m_dimm_bit_0 = atoi((*(++it)).c_str()); + } else if ( (*it) == "bank_queue_size" ) { + m_bank_queue_size = atoi((*(++it)).c_str()); + } else if ( (*it) == "bank_busy_time" ) { + m_bank_busy_time = atoi((*(++it)).c_str()); + } else if ( (*it) == "rank_rank_delay" ) { + m_rank_rank_delay = atoi((*(++it)).c_str()); + } else if ( (*it) == "read_write_delay" ) { + m_read_write_delay = atoi((*(++it)).c_str()); + } else if ( (*it) == "basic_bus_busy_time" ) { + m_basic_bus_busy_time = atoi((*(++it)).c_str()); + } else if ( (*it) == "mem_ctl_latency" ) { + m_mem_ctl_latency = atoi((*(++it)).c_str()); + } else if ( (*it) == "refresh_period" ) { + m_refresh_period = atoi((*(++it)).c_str()); + } else if ( (*it) == "tFaw" ) { + m_tFaw = atoi((*(++it)).c_str()); + } else if ( (*it) == "mem_random_arbitrate" ) { + m_mem_random_arbitrate = atoi((*(++it)).c_str()); + } else if ( (*it) == "mem_fixed_delay" ) { + m_mem_fixed_delay = atoi((*(++it)).c_str()); + } +// } else +// assert(0); + } + -MemoryControl::MemoryControl (AbstractChip* chip_ptr, int version) { - m_chip_ptr = chip_ptr; - m_version = version; +/////// + //m_version = version; m_msg_counter = 0; m_debug = 0; //if (m_version == 0) m_debug = 1; - m_mem_bus_cycle_multiplier = RubyConfig::memBusCycleMultiplier(); - m_banks_per_rank = RubyConfig::banksPerRank(); - m_ranks_per_dimm = RubyConfig::ranksPerDimm(); - m_dimms_per_channel = RubyConfig::dimmsPerChannel(); - m_bank_bit_0 = RubyConfig::bankBit0(); - m_rank_bit_0 = RubyConfig::rankBit0(); - m_dimm_bit_0 = RubyConfig::dimmBit0(); - m_bank_queue_size = RubyConfig::bankQueueSize(); - m_bank_busy_time = RubyConfig::bankBusyTime(); - m_rank_rank_delay = RubyConfig::rankRankDelay(); - m_read_write_delay = RubyConfig::readWriteDelay(); - m_basic_bus_busy_time = RubyConfig::basicBusBusyTime(); - m_mem_ctl_latency = RubyConfig::memCtlLatency(); - m_refresh_period = RubyConfig::refreshPeriod(); - m_memRandomArbitrate = RubyConfig::memRandomArbitrate(); - m_tFaw = RubyConfig::tFaw(); - m_memFixedDelay = RubyConfig::memFixedDelay(); assert(m_tFaw <= 62); // must fit in a uint64 shift register @@ -257,13 +291,15 @@ void MemoryControl::enqueueMemRef (MemoryNode& memRef) { Time arrival_time = memRef.m_time; uint64 at = arrival_time; bool is_mem_read = memRef.m_is_mem_read; + bool dirtyWB = memRef.m_is_dirty_wb; physical_address_t addr = memRef.m_addr; int bank = getBank(addr); if (m_debug) { - cprintf("New memory request%7d: %#08x %c arrived at %10d bank =%3x\n", - m_msg_counter, addr, is_mem_read? 'R':'W', at, bank); + printf("New memory request%7d: 0x%08llx %c arrived at %10lld ", m_msg_counter, addr, is_mem_read? 'R':'W', at); + printf("bank =%3x\n", bank); } - g_system_ptr->getProfiler()->profileMemReq(bank); +// printf ("m_name is %s \n", m_name.c_str()); + g_system_ptr->getProfiler()->profileMemReq(m_name, bank); m_input_queue.push_back(memRef); if (!m_awakened) { g_eventQueue_ptr->scheduleEvent(this, 1); @@ -295,7 +331,7 @@ MemoryNode MemoryControl::peekNode () { MemoryNode req = m_response_queue.front(); uint64 returnTime = req.m_time; if (m_debug) { - cprintf("Old memory request%7d: %#08x %c peeked at %10d\n", + printf("Old memory request%7d: 0x%08llx %c peeked at %10lld\n", req.m_msg_counter, req.m_addr, req.m_is_mem_read? 'R':'W', returnTime); } return req; @@ -319,10 +355,10 @@ void MemoryControl::printConfig (ostream& out) { out << "Memory Control " << m_version << ":" << endl; out << " Ruby cycles per memory cycle: " << m_mem_bus_cycle_multiplier << endl; out << " Basic read latency: " << m_mem_ctl_latency << endl; - if (m_memFixedDelay) { - out << " Fixed Latency mode: Added cycles = " << m_memFixedDelay << endl; + if (m_mem_fixed_delay) { + out << " Fixed Latency mode: Added cycles = " << m_mem_fixed_delay << endl; } else { - out << " Bank busy time: " << BANK_BUSY_TIME << " memory cycles" << endl; + out << " Bank busy time: " << m_bank_busy_time << " memory cycles" << endl; out << " Memory channel busy time: " << m_basic_bus_busy_time << endl; out << " Dead cycles between reads to different ranks: " << m_rank_rank_delay << endl; out << " Dead cycle between a read and a write: " << m_read_write_delay << endl; @@ -336,7 +372,7 @@ void MemoryControl::printConfig (ostream& out) { out << " LSB of DIMM field in address: " << m_dimm_bit_0 << endl; out << " Max size of each bank queue: " << m_bank_queue_size << endl; out << " Refresh period (within one bank): " << m_refresh_period << endl; - out << " Arbitration randomness: " << m_memRandomArbitrate << endl; + out << " Arbitration randomness: " << m_mem_random_arbitrate << endl; } @@ -389,20 +425,20 @@ int MemoryControl::getRank (int bank) { // can be issued this cycle bool MemoryControl::queueReady (int bank) { - if ((m_bankBusyCounter[bank] > 0) && !m_memFixedDelay) { - g_system_ptr->getProfiler()->profileMemBankBusy(); - //if (m_debug) cprintf(" bank %x busy %d\n", bank, m_bankBusyCounter[bank]); + if ((m_bankBusyCounter[bank] > 0) && !m_mem_fixed_delay) { + g_system_ptr->getProfiler()->profileMemBankBusy(m_name); + //if (m_debug) printf(" bank %x busy %d\n", bank, m_bankBusyCounter[bank]); return false; } - if (m_memRandomArbitrate >= 2) { - if ((random() % 100) < m_memRandomArbitrate) { - g_system_ptr->getProfiler()->profileMemRandBusy(); + if (m_mem_random_arbitrate >= 2) { + if ((random() % 100) < m_mem_random_arbitrate) { + g_system_ptr->getProfiler()->profileMemRandBusy(m_name); return false; } } - if (m_memFixedDelay) return true; + if (m_mem_fixed_delay) return true; if ((m_ageCounter > (2 * m_bank_busy_time)) && !m_oldRequest[bank]) { - g_system_ptr->getProfiler()->profileMemNotOld(); + g_system_ptr->getProfiler()->profileMemNotOld(m_name); return false; } if (m_busBusyCounter_Basic == m_basic_bus_busy_time) { @@ -411,26 +447,26 @@ bool MemoryControl::queueReady (int bank) { // a bus wait. This is a little inaccurate since it MIGHT // have also been blocked waiting for a read-write or a // read-read instead, but it's pretty close. - g_system_ptr->getProfiler()->profileMemArbWait(1); + g_system_ptr->getProfiler()->profileMemArbWait(m_name, 1); return false; } if (m_busBusyCounter_Basic > 0) { - g_system_ptr->getProfiler()->profileMemBusBusy(); + g_system_ptr->getProfiler()->profileMemBusBusy(m_name); return false; } int rank = getRank(bank); if (m_tfaw_count[rank] >= ACTIVATE_PER_TFAW) { - g_system_ptr->getProfiler()->profileMemTfawBusy(); + g_system_ptr->getProfiler()->profileMemTfawBusy(m_name); return false; } bool write = !m_bankQueues[bank].front().m_is_mem_read; if (write && (m_busBusyCounter_Write > 0)) { - g_system_ptr->getProfiler()->profileMemReadWriteBusy(); + g_system_ptr->getProfiler()->profileMemReadWriteBusy(m_name); return false; } if (!write && (rank != m_busBusy_WhichRank) && (m_busBusyCounter_ReadNewRank > 0)) { - g_system_ptr->getProfiler()->profileMemDataBusBusy(); + g_system_ptr->getProfiler()->profileMemDataBusBusy(m_name); return false; } return true; @@ -453,9 +489,9 @@ bool MemoryControl::issueRefresh (int bank) { //if (m_debug) { //uint64 current_time = g_eventQueue_ptr->getTime(); - //cprintf(" Refresh bank %3x at %d\n", bank, current_time); + //printf(" Refresh bank %3x at %lld\n", bank, current_time); //} - g_system_ptr->getProfiler()->profileMemRefresh(); + g_system_ptr->getProfiler()->profileMemRefresh(m_name); m_need_refresh--; m_refresh_bank++; if (m_refresh_bank >= m_total_banks) m_refresh_bank = 0; @@ -488,23 +524,23 @@ void MemoryControl::issueRequest (int bank) { m_bankQueues[bank].pop_front(); if (m_debug) { uint64 current_time = g_eventQueue_ptr->getTime(); - cprintf(" Mem issue request%7d: %#08x %c at %10d bank =%3x\n", + printf(" Mem issue request%7d: 0x%08llx %c at %10lld bank =%3x\n", req.m_msg_counter, req.m_addr, req.m_is_mem_read? 'R':'W', current_time, bank); } if (req.m_msgptr.ref() != NULL) { // don't enqueue L3 writebacks - enqueueToDirectory(req, m_mem_ctl_latency + m_memFixedDelay); + enqueueToDirectory(req, m_mem_ctl_latency + m_mem_fixed_delay); } m_oldRequest[bank] = 0; markTfaw(rank); m_bankBusyCounter[bank] = m_bank_busy_time; m_busBusy_WhichRank = rank; if (req.m_is_mem_read) { - g_system_ptr->getProfiler()->profileMemRead(); + g_system_ptr->getProfiler()->profileMemRead(m_name); m_busBusyCounter_Basic = m_basic_bus_busy_time; m_busBusyCounter_Write = m_basic_bus_busy_time + m_read_write_delay; m_busBusyCounter_ReadNewRank = m_basic_bus_busy_time + m_rank_rank_delay; } else { - g_system_ptr->getProfiler()->profileMemWrite(); + g_system_ptr->getProfiler()->profileMemWrite(m_name); m_busBusyCounter_Basic = m_basic_bus_busy_time; m_busBusyCounter_Write = m_basic_bus_busy_time; m_busBusyCounter_ReadNewRank = m_basic_bus_busy_time; @@ -531,8 +567,8 @@ void MemoryControl::executeCycle () { } // After time period expires, latch an indication that we need a refresh. - // Disable refresh if in memFixedDelay mode. - if (!m_memFixedDelay) m_refresh_count--; + // Disable refresh if in mem_fixed_delay mode. + if (!m_mem_fixed_delay) m_refresh_count--; if (m_refresh_count == 0) { m_refresh_count = m_refresh_period_system; assert (m_need_refresh < 10); // Are we overrunning our ability to refresh? @@ -553,7 +589,7 @@ void MemoryControl::executeCycle () { } // If randomness desired, re-randomize round-robin position each cycle - if (m_memRandomArbitrate) { + if (m_mem_random_arbitrate) { m_roundRobin = random() % m_total_banks; } @@ -562,7 +598,7 @@ void MemoryControl::executeCycle () { // request and issue it. Treat a refresh request as if it // were at the head of its bank queue. After we issue something, // keep scanning the queues just to gather statistics about - // how many are waiting. If in memFixedDelay mode, we can issue + // how many are waiting. If in mem_fixed_delay mode, we can issue // more than one request per cycle. int queueHeads = 0; @@ -573,7 +609,7 @@ void MemoryControl::executeCycle () { issueRefresh(m_roundRobin); int qs = m_bankQueues[m_roundRobin].size(); if (qs > 1) { - g_system_ptr->getProfiler()->profileMemBankQ(qs-1); + g_system_ptr->getProfiler()->profileMemBankQ(m_name, qs-1); } if (qs > 0) { m_idleCount = IDLECOUNT_MAX_VALUE; // we're not idle if anything is queued @@ -581,15 +617,15 @@ void MemoryControl::executeCycle () { if (queueReady(m_roundRobin)) { issueRequest(m_roundRobin); banksIssued++; - if (m_memFixedDelay) { - g_system_ptr->getProfiler()->profileMemWaitCycles(m_memFixedDelay); + if (m_mem_fixed_delay) { + g_system_ptr->getProfiler()->profileMemWaitCycles(m_name, m_mem_fixed_delay); } } } } // memWaitCycles is a redundant catch-all for the specific counters in queueReady - g_system_ptr->getProfiler()->profileMemWaitCycles(queueHeads - banksIssued); + g_system_ptr->getProfiler()->profileMemWaitCycles(m_name, queueHeads - banksIssued); // Check input queue and move anything to bank queues if not full. // Since this is done here at the end of the cycle, there will always @@ -606,7 +642,7 @@ void MemoryControl::executeCycle () { m_input_queue.pop_front(); m_bankQueues[bank].push_back(req); } - g_system_ptr->getProfiler()->profileMemInputQ(m_input_queue.size()); + g_system_ptr->getProfiler()->profileMemInputQ(m_name, m_input_queue.size()); } } diff --git a/src/mem/ruby/system/MemoryControl.hh b/src/mem/ruby/system/MemoryControl.hh index aef2edc5b..3419f8c40 100644 --- a/src/mem/ruby/system/MemoryControl.hh +++ b/src/mem/ruby/system/MemoryControl.hh @@ -43,7 +43,6 @@ #include "mem/gems_common/Map.hh" #include "mem/ruby/common/Address.hh" #include "mem/ruby/profiler/Profiler.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" #include "mem/ruby/system/System.hh" #include "mem/ruby/slicc_interface/Message.hh" #include "mem/gems_common/util.hh" @@ -67,7 +66,8 @@ class MemoryControl : public Consumer, public AbstractMemOrCache { public: // Constructors - MemoryControl (AbstractChip* chip_ptr, int version); + MemoryControl(const string & name); + void init(const vector<string> & argv); // Destructor ~MemoryControl (); @@ -78,8 +78,8 @@ public: void setConsumer (Consumer* consumer_ptr); Consumer* getConsumer () { return m_consumer_ptr; }; - void setDescription (const string& name) { m_name = name; }; - string getDescription () { return m_name; }; + void setDescription (const string& name) { m_description = name; }; + string getDescription () { return m_description; }; // Called from the directory: void enqueue (const MsgPtr& message, int latency ); @@ -97,6 +97,12 @@ public: void print (ostream& out) const; void setDebug (int debugFlag); + + //added by SS + int getBanksPerRank() { return m_banks_per_rank; }; + int getRanksPerDimm() { return m_ranks_per_dimm; }; + int getDimmsPerChannel() { return m_dimms_per_channel; } + private: void enqueueToDirectory (MemoryNode req, int latency); @@ -113,9 +119,9 @@ private: MemoryControl& operator=(const MemoryControl& obj); // data members - AbstractChip* m_chip_ptr; Consumer* m_consumer_ptr; // Consumer to signal a wakeup() string m_name; + string m_description; int m_version; int m_msg_counter; int m_awakened; @@ -134,9 +140,9 @@ private: int m_basic_bus_busy_time; int m_mem_ctl_latency; int m_refresh_period; - int m_memRandomArbitrate; + int m_mem_random_arbitrate; int m_tFaw; - int m_memFixedDelay; + int m_mem_fixed_delay; int m_total_banks; int m_total_ranks; diff --git a/src/mem/ruby/system/MemoryVector.hh b/src/mem/ruby/system/MemoryVector.hh new file mode 100644 index 000000000..c5f3cea7f --- /dev/null +++ b/src/mem/ruby/system/MemoryVector.hh @@ -0,0 +1,81 @@ + +#ifndef MEMORYVECTOR_H +#define MEMORYVECTOR_H + +#include "mem/ruby/common/Address.hh" + +class DirectoryMemory; + +/** + * MemoryVector holds memory data (DRAM only) + */ +class MemoryVector { + public: + MemoryVector(); + MemoryVector(uint32 size); + ~MemoryVector(); + friend class DirectoryMemory; + + void setSize(uint32 size); // destructive + + void write(const Address & paddr, uint8* data, int len); + uint8* read(const Address & paddr, uint8* data, int len); + + private: + uint8* getBlockPtr(const Address & paddr); + + uint32 m_size; + uint8* m_vec; +}; + +inline +MemoryVector::MemoryVector() +{ + m_size = 0; + m_vec = NULL; +} + +inline +MemoryVector::MemoryVector(uint32 size) +{ + m_size = size; + m_vec = new uint8[size]; +} + +inline +MemoryVector::~MemoryVector() +{ + delete [] m_vec; +} + +inline +void MemoryVector::setSize(uint32 size) +{ + m_size = size; + if (m_vec != NULL) + delete [] m_vec; + m_vec = new uint8[size]; +} + +inline +void MemoryVector::write(const Address & paddr, uint8* data, int len) +{ + assert(paddr.getAddress() + len <= m_size); + memcpy(m_vec + paddr.getAddress(), data, len); +} + +inline +uint8* MemoryVector::read(const Address & paddr, uint8* data, int len) +{ + assert(paddr.getAddress() + len <= m_size); + memcpy(data, m_vec + paddr.getAddress(), len); + return data; +} + +inline +uint8* MemoryVector::getBlockPtr(const Address & paddr) +{ + return m_vec + paddr.getAddress(); +} + +#endif // MEMORYVECTOR_H diff --git a/src/mem/ruby/system/NodePersistentTable.cc b/src/mem/ruby/system/NodePersistentTable.cc deleted file mode 100644 index 4dd5c670f..000000000 --- a/src/mem/ruby/system/NodePersistentTable.cc +++ /dev/null @@ -1,193 +0,0 @@ - -/* - * 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. - */ - -/* - * $Id: NodePersistentTable.C 1.3 04/08/16 14:12:33-05:00 beckmann@c2-143.cs.wisc.edu $ - * - */ - -#include "mem/ruby/system/NodePersistentTable.hh" -#include "mem/ruby/common/Set.hh" -#include "mem/gems_common/Map.hh" -#include "mem/ruby/common/Address.hh" -#include "mem/ruby/slicc_interface/AbstractChip.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}; - - -class NodePersistentTableEntry { -public: - Set m_starving; - Set m_marked; - Set m_request_to_write; -}; - -NodePersistentTable::NodePersistentTable(AbstractChip* chip_ptr, int version) -{ - m_chip_ptr = chip_ptr; - m_map_ptr = new Map<Address, NodePersistentTableEntry>; - m_version = version; -} - -NodePersistentTable::~NodePersistentTable() -{ - delete m_map_ptr; - m_map_ptr = NULL; - m_chip_ptr = NULL; -} - -void NodePersistentTable::persistentRequestLock(const Address& address, NodeID llocker, AccessType type) -{ - - // if (locker == m_chip_ptr->getID() ) - // cout << "Chip " << m_chip_ptr->getID() << ": " << llocker << " requesting lock for " << address << endl; - - NodeID locker = (NodeID) persistent_randomize[llocker]; - - assert(address == line_address(address)); - if (!m_map_ptr->exist(address)) { - // Allocate if not present - NodePersistentTableEntry entry; - entry.m_starving.add(locker); - if (type == AccessType_Write) { - entry.m_request_to_write.add(locker); - } - m_map_ptr->add(address, entry); - } else { - NodePersistentTableEntry& entry = m_map_ptr->lookup(address); - assert(!(entry.m_starving.isElement(locker))); // Make sure we're not already in the locked set - - 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 NodePersistentTable::persistentRequestUnlock(const Address& address, NodeID uunlocker) -{ - // if (unlocker == m_chip_ptr->getID() ) - // cout << "Chip " << m_chip_ptr->getID() << ": " << uunlocker << " requesting unlock for " << address << endl; - - NodeID unlocker = (NodeID) persistent_randomize[uunlocker]; - - assert(address == line_address(address)); - assert(m_map_ptr->exist(address)); - NodePersistentTableEntry& entry = m_map_ptr->lookup(address); - assert(entry.m_starving.isElement(unlocker)); // Make sure we're in the locked set - 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 NodePersistentTable::okToIssueStarving(const Address& address) const -{ - assert(address == line_address(address)); - if (!m_map_ptr->exist(address)) { - return true; // No entry present - } else if (m_map_ptr->lookup(address).m_starving.isElement(m_chip_ptr->getID())) { - return false; // We can't issue another lockdown until are previous unlock has occurred - } else { - return (m_map_ptr->lookup(address).m_marked.isEmpty()); - } -} - -NodeID NodePersistentTable::findSmallest(const Address& address) const -{ - assert(address == line_address(address)); - assert(m_map_ptr->exist(address)); - const NodePersistentTableEntry& entry = m_map_ptr->lookup(address); - // cout << "Node " << m_chip_ptr->getID() << " returning " << persistent_randomize[entry.m_starving.smallestElement()] << " for findSmallest(" << address << ")" << endl; - return (NodeID) persistent_randomize[entry.m_starving.smallestElement()]; -} - -AccessType NodePersistentTable::typeOfSmallest(const Address& address) const -{ - assert(address == line_address(address)); - assert(m_map_ptr->exist(address)); - const NodePersistentTableEntry& 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 NodePersistentTable::markEntries(const Address& address) -{ - assert(address == line_address(address)); - if (m_map_ptr->exist(address)) { - NodePersistentTableEntry& entry = m_map_ptr->lookup(address); - assert(entry.m_marked.isEmpty()); // None should be marked - entry.m_marked = entry.m_starving; // Mark all the nodes currently in the table - } -} - -bool NodePersistentTable::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 NodePersistentTable::countStarvingForAddress(const Address& address) const -{ - if (m_map_ptr->exist(address)) { - NodePersistentTableEntry& entry = m_map_ptr->lookup(address); - return (entry.m_starving.count()); - } - else { - return 0; - } -} - -int NodePersistentTable::countReadStarvingForAddress(const Address& address) const -{ - if (m_map_ptr->exist(address)) { - NodePersistentTableEntry& entry = m_map_ptr->lookup(address); - return (entry.m_starving.count() - entry.m_request_to_write.count()); - } - else { - return 0; - } -} - - diff --git a/src/mem/ruby/system/NodePersistentTable.hh b/src/mem/ruby/system/NodePersistentTable.hh deleted file mode 100644 index d731b25ae..000000000 --- a/src/mem/ruby/system/NodePersistentTable.hh +++ /dev/null @@ -1,99 +0,0 @@ - -/* - * 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. - */ - -/* - * $Id: NodePersistentTable.hh 1.3 04/08/16 14:12:33-05:00 beckmann@c2-143.cs.wisc.edu $ - * - * Description: - * - */ - -#ifndef NodePersistentTable_H -#define NodePersistentTable_H - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/system/NodeID.hh" -#include "mem/protocol/AccessType.hh" - -class AbstractChip; - -template <class KEY_TYPE, class VALUE_TYPE> class Map; -class Address; -class NodePersistentTableEntry; - -class NodePersistentTable { -public: - // Constructors - NodePersistentTable(AbstractChip* chip_ptr, int version); - - // Destructor - ~NodePersistentTable(); - - // Public Methods - void persistentRequestLock(const Address& address, NodeID locker, AccessType type); - void persistentRequestUnlock(const Address& address, NodeID unlocker); - bool okToIssueStarving(const Address& address) const; - NodeID 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 - NodePersistentTable(const NodePersistentTable& obj); - NodePersistentTable& operator=(const NodePersistentTable& obj); - - // Data Members (m_prefix) - Map<Address, NodePersistentTableEntry>* m_map_ptr; - AbstractChip* m_chip_ptr; - int m_version; -}; - -// Output operator declaration -ostream& operator<<(ostream& out, const NodePersistentTable& obj); - -// ******************* Definitions ******************* - -// Output operator definition -extern inline -ostream& operator<<(ostream& out, const NodePersistentTable& obj) -{ - obj.print(out); - out << flush; - return out; -} - -#endif //NodePersistentTable_H diff --git a/src/mem/ruby/system/PersistentArbiter.cc b/src/mem/ruby/system/PersistentArbiter.cc deleted file mode 100644 index b44393301..000000000 --- a/src/mem/ruby/system/PersistentArbiter.cc +++ /dev/null @@ -1,165 +0,0 @@ - -/* - * 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/PersistentArbiter.hh" -#include "mem/ruby/common/Address.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" -#include "mem/gems_common/util.hh" - -PersistentArbiter::PersistentArbiter(AbstractChip* chip_ptr) -{ - m_chip_ptr = chip_ptr; - - // wastes entries, but who cares - m_entries.setSize(RubyConfig::numberOfProcessors()); - - for (int i = 0; i < m_entries.size(); i++) { - m_entries[i].valid = false; - } - - m_busy = false; - m_locker = -1; - -} - -PersistentArbiter::~PersistentArbiter() -{ - m_chip_ptr = NULL; -} - - -void PersistentArbiter::addLocker(NodeID id, Address addr, AccessType type) { - //cout << "Arbiter " << getArbiterId() << " adding locker " << id << " " << addr << endl; - assert(m_entries[id].valid == false); - m_entries[id].valid = true; - m_entries[id].address = addr; - m_entries[id].type = type; - m_entries[id].localId = id; - -} - -void PersistentArbiter::removeLocker(NodeID id) { - //cout << "Arbiter " << getArbiterId() << " removing locker " << id << " " << m_entries[id].address << endl; - assert(m_entries[id].valid == true); - m_entries[id].valid = false; - - if (!lockersExist()) { - m_busy = false; - } -} - -bool PersistentArbiter::successorRequestPresent(Address addr, NodeID id) { - for (int i = (id + 1); i < m_entries.size(); i++) { - if (m_entries[i].address == addr && m_entries[i].valid) { - //cout << "m_entries[" << id << ", address " << m_entries[id].address << " is equal to " << addr << endl; - return true; - } - } - return false; -} - -bool PersistentArbiter::lockersExist() { - for (int i = 0; i < m_entries.size(); i++) { - if (m_entries[i].valid == true) { - return true; - } - } - //cout << "no lockers found" << endl; - return false; -} - -void PersistentArbiter::advanceActiveLock() { - assert(lockersExist()); - - //cout << "arbiter advancing lock from " << m_locker; - m_busy = false; - - if (m_locker < (m_entries.size() - 1)) { - for (int i = (m_locker+1); i < m_entries.size(); i++) { - if (m_entries[i].valid == true) { - m_locker = i; - m_busy = true; - //cout << " to " << m_locker << endl; - return; - } - } - } - - if (!m_busy) { - for (int i = 0; i < m_entries.size(); i++) { - if (m_entries[i].valid == true) { - m_locker = i; - m_busy = true; - //cout << " to " << m_locker << endl; - return; - } - } - - assert(m_busy) - } -} - -Address PersistentArbiter::getActiveLockAddress() { - assert( m_entries[m_locker].valid = true ); - return m_entries[m_locker].address; -} - - -NodeID PersistentArbiter::getArbiterId() { - return m_chip_ptr->getID()*RubyConfig::numberOfProcsPerChip(); -} - -bool PersistentArbiter::isBusy() { - return m_busy; -} - -NodeID PersistentArbiter::getActiveLocalId() { - assert( m_entries[m_locker].valid = true ); - return m_entries[m_locker].localId; -} - -void PersistentArbiter::setIssuedAddress(Address addr) { - m_issued_address = addr; -} - -bool PersistentArbiter::isIssuedAddress(Address addr) { - return (m_issued_address == addr); -} - -void PersistentArbiter::print(ostream& out) const { - - out << "["; - for (int i = 0; i < m_entries.size(); i++) { - if (m_entries[i].valid == true) { - out << "( " << m_entries[i].localId << ", " << m_entries[i].address << ") "; - } - } - out << "]" << endl; - -} diff --git a/src/mem/ruby/system/PersistentArbiter.hh b/src/mem/ruby/system/PersistentArbiter.hh deleted file mode 100644 index 1ce05f51f..000000000 --- a/src/mem/ruby/system/PersistentArbiter.hh +++ /dev/null @@ -1,107 +0,0 @@ - -/* - * 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. - */ - -/* - * PersistentArbiter.hh - * - * Description: - * - * Used for hierarchical distributed persistent request scheme - * - */ - -#ifndef PERSISTENTARBITER_H -#define PERSISTENTARBITER_H - -#include "mem/ruby/common/Global.hh" -#include "mem/gems_common/Vector.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" -#include "mem/protocol/AccessPermission.hh" -#include "mem/protocol/AccessType.hh" -#include "mem/ruby/config/RubyConfig.hh" -#include "mem/ruby/common/Address.hh" - -struct ArbiterEntry { - bool valid; - Address address; - AccessType type; - NodeID localId; -}; - -class PersistentArbiter { -public: - - // Constructors - PersistentArbiter(AbstractChip* chip_ptr); - - // Destructor - ~PersistentArbiter(); - - // Public Methods - - void addLocker(NodeID id, Address addr, AccessType type); - void removeLocker(NodeID id); - bool successorRequestPresent(Address addr, NodeID id); - bool lockersExist(); - void advanceActiveLock(); - Address getActiveLockAddress(); - NodeID getArbiterId(); - bool isBusy(); - - void setIssuedAddress(Address addr); - bool isIssuedAddress(Address addr); - - - Address getIssuedAddress() { return m_issued_address; } - - static void printConfig(ostream& out) {} - void print(ostream& out) const; - - NodeID getActiveLocalId(); - -private: - - Address m_issued_address; - AbstractChip* m_chip_ptr; - int m_locker; - bool m_busy; - Vector<ArbiterEntry> m_entries; -}; - -// Output operator definition -extern inline -ostream& operator<<(ostream& out, const PersistentArbiter& obj) -{ - obj.print(out); - out << flush; - return out; -} - - -#endif //PERFECTCACHEMEMORY_H diff --git a/src/mem/ruby/system/PersistentTable.cc b/src/mem/ruby/system/PersistentTable.cc deleted file mode 100644 index 7f07251ce..000000000 --- a/src/mem/ruby/system/PersistentTable.cc +++ /dev/null @@ -1,194 +0,0 @@ - -/* - * 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. - */ - -/* - * $Id$ - * - */ - -#include "mem/ruby/system/PersistentTable.hh" -#include "mem/ruby/common/NetDest.hh" -#include "mem/gems_common/Map.hh" -#include "mem/ruby/common/Address.hh" -#include "mem/ruby/slicc_interface/AbstractChip.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}; - - -class PersistentTableEntry { -public: - NetDest m_starving; - NetDest m_marked; - NetDest m_request_to_write; -}; - -PersistentTable::PersistentTable(AbstractChip* chip_ptr, int version) -{ - m_chip_ptr = chip_ptr; - m_map_ptr = new Map<Address, PersistentTableEntry>; - m_version = version; -} - -PersistentTable::~PersistentTable() -{ - delete m_map_ptr; - m_map_ptr = NULL; - m_chip_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); - assert(!(entry.m_starving.isElement(locker))); // Make sure we're not already in the locked set - - 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); - assert(entry.m_starving.isElement(unlocker)); // Make sure we're in the locked set - 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) const -{ - assert(address == line_address(address)); - if (!m_map_ptr->exist(address)) { - return true; // No entry present - } else if (m_map_ptr->lookup(address).m_starving.isElement( (MachineID) {MachineType_L1Cache, m_version})) { - return false; // We can't issue another lockdown until are previous unlock has occurred - } 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); - // cout << "Node " << m_chip_ptr->getID() << " returning " << persistent_randomize[entry.m_starving.smallestElement()] << " for findSmallest(" << address << ")" << endl; - // return (MachineID) persistent_randomize[entry.m_starving.smallestElement()]; - return (MachineID) { MachineType_L1Cache, 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((MachineID) {MachineType_L1Cache, 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); - assert(entry.m_marked.isEmpty()); // None should be marked - entry.m_marked = entry.m_starving; // Mark all the nodes currently in the table - } -} - -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; - } -} - - diff --git a/src/mem/ruby/system/PersistentTable.hh b/src/mem/ruby/system/PersistentTable.hh deleted file mode 100644 index 9f2e38fd7..000000000 --- a/src/mem/ruby/system/PersistentTable.hh +++ /dev/null @@ -1,99 +0,0 @@ - -/* - * 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. - */ - -/* - * $Id$ - * - * Description: - * - */ - -#ifndef PersistentTable_H -#define PersistentTable_H - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/system/MachineID.hh" -#include "mem/protocol/AccessType.hh" - -class AbstractChip; - -template <class KEY_TYPE, class VALUE_TYPE> class Map; -class Address; -class PersistentTableEntry; - -class PersistentTable { -public: - // Constructors - PersistentTable(AbstractChip* chip_ptr, int version); - - // 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) 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; - AbstractChip* m_chip_ptr; - int m_version; -}; - -// Output operator declaration -ostream& operator<<(ostream& out, const PersistentTable& obj); - -// ******************* Definitions ******************* - -// Output operator definition -extern inline -ostream& operator<<(ostream& out, const PersistentTable& obj) -{ - obj.print(out); - out << flush; - return out; -} - -#endif //PersistentTable_H diff --git a/src/mem/ruby/system/ProcessorInterface.hh b/src/mem/ruby/system/ProcessorInterface.hh new file mode 100644 index 000000000..d76e29f65 --- /dev/null +++ b/src/mem/ruby/system/ProcessorInterface.hh @@ -0,0 +1,45 @@ + +struct ProcessorRequest { + vector<CacheRequest*> cache_requests; +}; + +class ProcessorInterface { + +public: + + void read_atomic(const Address & paddr, void* data, int len) { + assert(paddr.getLineAddress() + RubyConfig::dataBlockBytes() >= paddr + len); + // for now, atomics can't span two blocks. Maybe fix this later + } + + void read(const Address & paddr, const Address & rip, AccessModeType atype, void* data, const int len) { + + // create the CacheRequests + ProcessorRequest* this_request = new ProcessorRequest; + Address split_addr = paddr; + int len_remaining = len; + while (split_addr.getAddress() < paddr.getAddress() + len) { + int split_len = (split_addr.getAddress() + len_remaining <= split_addr.getLineAddress() + RubyConfig::dataBlockBytes()) ? + len_remaining : + RubyConfig::dataBlockBytes() - split_addr.getOffset(); + CacheRequest creq = new CacheRequest( line_address(split_addr), + split_addr, + CacheRequestType_LD, + rip, + atype, + split_len, + PretchBit_No, + laddr, + 0); // SMT thread id); + this_request->cache_requests.push_back(creq); + split_addr += split_len; + len_remaining -= split_len; + } + outstanding_requests.push_back(this_request); + + } + +private: + vector<ProcessorRequest*> outstanding_requests; + Sequencer* m_sequencer; +}; diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc new file mode 100644 index 000000000..2a5c5f479 --- /dev/null +++ b/src/mem/ruby/system/RubyPort.cc @@ -0,0 +1,5 @@ + +#include "mem/ruby/system/RubyPort.hh" + +//void (*RubyPort::m_hit_callback)(int64_t) = NULL; +uint16_t RubyPort::m_num_ports = 0; diff --git a/src/mem/ruby/system/RubyPort.hh b/src/mem/ruby/system/RubyPort.hh new file mode 100644 index 000000000..2f391070f --- /dev/null +++ b/src/mem/ruby/system/RubyPort.hh @@ -0,0 +1,60 @@ +#ifndef RUBYPORT_H +#define RUBYPORT_H + +#include "mem/ruby/libruby.hh" +#include <string> +#include <assert.h> + +using namespace std; + +class RubyPort { +public: + RubyPort(const string & name) + : m_name(name) + { + m_port_id = m_num_ports++; + m_request_cnt = 0; + m_hit_callback = NULL; + assert(m_num_ports <= 2048); // see below for reason + } + virtual ~RubyPort() {} + + virtual int64_t makeRequest(const RubyRequest & request) = 0; + + void registerHitCallback(void (*hit_callback)(int64_t request_id)) { + assert(m_hit_callback == NULL); // can't assign hit_callback twice + m_hit_callback = hit_callback; + } + +protected: + const string m_name; + void (*m_hit_callback)(int64_t); + + int64_t makeUniqueRequestID() { + // The request ID is generated by combining the port ID with a request count + // so that request IDs can be formed concurrently by multiple threads. + // IDs are formed as follows: + // + // + // 0 PortID Request Count + // +----+---------------+-----------------------------------------------------+ + // | 63 | 62-48 | 47-0 | + // +----+---------------+-----------------------------------------------------+ + // + // + // This limits the system to a maximum of 2^11 == 2048 components + // and 2^48 ~= 3x10^14 requests per component + + int64_t id = (static_cast<uint64_t>(m_port_id) << 48) | m_request_cnt; + m_request_cnt++; + // assert((m_request_cnt & (1<<48)) == 0); + return id; + } + +private: + static uint16_t m_num_ports; + uint16_t m_port_id; + uint64_t m_request_cnt; +}; + +#endif diff --git a/src/mem/ruby/system/Sequencer.cc b/src/mem/ruby/system/Sequencer.cc index 82eef2901..ff5ce1506 100644 --- a/src/mem/ruby/system/Sequencer.cc +++ b/src/mem/ruby/system/Sequencer.cc @@ -27,909 +27,424 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* - * $Id: Sequencer.C 1.131 2006/11/06 17:41:01-06:00 bobba@gratiano.cs.wisc.edu $ - * - */ - #include "mem/ruby/common/Global.hh" #include "mem/ruby/system/Sequencer.hh" #include "mem/ruby/system/System.hh" #include "mem/protocol/Protocol.hh" #include "mem/ruby/profiler/Profiler.hh" #include "mem/ruby/system/CacheMemory.hh" -#include "mem/ruby/config/RubyConfig.hh" -//#include "mem/ruby/recorder/Tracer.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" -#include "mem/protocol/Chip.hh" -#include "mem/ruby/tester/Tester.hh" +#include "mem/protocol/CacheMsg.hh" +#include "mem/ruby/recorder/Tracer.hh" #include "mem/ruby/common/SubBlock.hh" #include "mem/protocol/Protocol.hh" #include "mem/gems_common/Map.hh" -#include "mem/packet.hh" +#include "mem/ruby/buffers/MessageBuffer.hh" +#include "mem/ruby/slicc_interface/AbstractController.hh" -Sequencer::Sequencer(AbstractChip* chip_ptr, int version) { - m_chip_ptr = chip_ptr; - m_version = version; +//Sequencer::Sequencer(int core_id, MessageBuffer* mandatory_q) +Sequencer::Sequencer(const string & name) + :RubyPort(name) +{ +} + +void Sequencer::init(const vector<string> & argv) +{ m_deadlock_check_scheduled = false; m_outstanding_count = 0; - int smt_threads = RubyConfig::numberofSMTThreads(); - m_writeRequestTable_ptr = new Map<Address, CacheMsg>*[smt_threads]; - m_readRequestTable_ptr = new Map<Address, CacheMsg>*[smt_threads]; - - m_packetTable_ptr = new Map<Address, Packet*>; - - for(int p=0; p < smt_threads; ++p){ - m_writeRequestTable_ptr[p] = new Map<Address, CacheMsg>; - m_readRequestTable_ptr[p] = new Map<Address, CacheMsg>; + m_max_outstanding_requests = 0; + m_deadlock_threshold = 0; + m_version = -1; + m_instCache_ptr = NULL; + m_dataCache_ptr = NULL; + m_controller = NULL; + for (size_t i=0; i<argv.size(); i+=2) { + if ( argv[i] == "controller") { + m_controller = RubySystem::getController(argv[i+1]); // args[i] = "L1Cache" + m_mandatory_q_ptr = m_controller->getMandatoryQueue(); + } else if ( argv[i] == "icache") + m_instCache_ptr = RubySystem::getCache(argv[i+1]); + else if ( argv[i] == "dcache") + m_dataCache_ptr = RubySystem::getCache(argv[i+1]); + else if ( argv[i] == "version") + m_version = atoi(argv[i+1].c_str()); + else if ( argv[i] == "max_outstanding_requests") + m_max_outstanding_requests = atoi(argv[i+1].c_str()); + else if ( argv[i] == "deadlock_threshold") + m_deadlock_threshold = atoi(argv[i+1].c_str()); + else { + cerr << "WARNING: Sequencer: Unkown configuration parameter: " << argv[i] << endl; + assert(false); + } } - + assert(m_max_outstanding_requests > 0); + assert(m_deadlock_threshold > 0); + assert(m_version > -1); + assert(m_instCache_ptr != NULL); + assert(m_dataCache_ptr != NULL); + assert(m_controller != NULL); } Sequencer::~Sequencer() { - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int i=0; i < smt_threads; ++i){ - if(m_writeRequestTable_ptr[i]){ - delete m_writeRequestTable_ptr[i]; - } - if(m_readRequestTable_ptr[i]){ - delete m_readRequestTable_ptr[i]; - } - } - if(m_writeRequestTable_ptr){ - delete [] m_writeRequestTable_ptr; - } - if(m_readRequestTable_ptr){ - delete [] m_readRequestTable_ptr; - } + } void Sequencer::wakeup() { // Check for deadlock of any of the requests Time current_time = g_eventQueue_ptr->getTime(); - bool deadlock = false; // Check across all outstanding requests - int smt_threads = RubyConfig::numberofSMTThreads(); int total_outstanding = 0; - for(int p=0; p < smt_threads; ++p){ - Vector<Address> keys = m_readRequestTable_ptr[p]->keys(); - for (int i=0; i<keys.size(); i++) { - CacheMsg& request = m_readRequestTable_ptr[p]->lookup(keys[i]); - if (current_time - request.getTime() >= g_DEADLOCK_THRESHOLD) { - WARN_MSG("Possible Deadlock detected"); - WARN_EXPR(request); - WARN_EXPR(m_chip_ptr->getID()); - WARN_EXPR(m_version); - WARN_EXPR(keys.size()); - WARN_EXPR(current_time); - WARN_EXPR(request.getTime()); - WARN_EXPR(current_time - request.getTime()); - WARN_EXPR(*m_readRequestTable_ptr[p]); - ERROR_MSG("Aborting"); - deadlock = true; - } - } - keys = m_writeRequestTable_ptr[p]->keys(); - for (int i=0; i<keys.size(); i++) { - CacheMsg& request = m_writeRequestTable_ptr[p]->lookup(keys[i]); - if (current_time - request.getTime() >= g_DEADLOCK_THRESHOLD) { - WARN_MSG("Possible Deadlock detected"); - WARN_EXPR(request); - WARN_EXPR(m_chip_ptr->getID()); - WARN_EXPR(m_version); - WARN_EXPR(current_time); - WARN_EXPR(request.getTime()); - WARN_EXPR(current_time - request.getTime()); - WARN_EXPR(keys.size()); - WARN_EXPR(*m_writeRequestTable_ptr[p]); - ERROR_MSG("Aborting"); - deadlock = true; - } - } - total_outstanding += m_writeRequestTable_ptr[p]->size() + m_readRequestTable_ptr[p]->size(); - } // across all request tables + Vector<Address> keys = m_readRequestTable.keys(); + for (int i=0; i<keys.size(); i++) { + SequencerRequest* request = m_readRequestTable.lookup(keys[i]); + if (current_time - request->issue_time >= m_deadlock_threshold) { + WARN_MSG("Possible Deadlock detected"); + WARN_EXPR(request); + WARN_EXPR(m_version); + WARN_EXPR(keys.size()); + WARN_EXPR(current_time); + WARN_EXPR(request->issue_time); + WARN_EXPR(current_time - request->issue_time); + ERROR_MSG("Aborting"); + } + } + + keys = m_writeRequestTable.keys(); + for (int i=0; i<keys.size(); i++) { + SequencerRequest* request = m_writeRequestTable.lookup(keys[i]); + if (current_time - request->issue_time >= m_deadlock_threshold) { + WARN_MSG("Possible Deadlock detected"); + WARN_EXPR(request); + WARN_EXPR(m_version); + WARN_EXPR(current_time); + WARN_EXPR(request->issue_time); + WARN_EXPR(current_time - request->issue_time); + WARN_EXPR(keys.size()); + ERROR_MSG("Aborting"); + } + } + total_outstanding += m_writeRequestTable.size() + m_readRequestTable.size(); + assert(m_outstanding_count == total_outstanding); if (m_outstanding_count > 0) { // If there are still outstanding requests, keep checking - g_eventQueue_ptr->scheduleEvent(this, g_DEADLOCK_THRESHOLD); + g_eventQueue_ptr->scheduleEvent(this, m_deadlock_threshold); } else { m_deadlock_check_scheduled = false; } } -//returns the total number of requests -int Sequencer::getNumberOutstanding(){ - return m_outstanding_count; -} - -// returns the total number of demand requests -int Sequencer::getNumberOutstandingDemand(){ - int smt_threads = RubyConfig::numberofSMTThreads(); - int total_demand = 0; - for(int p=0; p < smt_threads; ++p){ - Vector<Address> keys = m_readRequestTable_ptr[p]->keys(); - for (int i=0; i< keys.size(); i++) { - CacheMsg& request = m_readRequestTable_ptr[p]->lookup(keys[i]); - if(request.getPrefetch() == PrefetchBit_No){ - total_demand++; - } - } - - keys = m_writeRequestTable_ptr[p]->keys(); - for (int i=0; i< keys.size(); i++) { - CacheMsg& request = m_writeRequestTable_ptr[p]->lookup(keys[i]); - if(request.getPrefetch() == PrefetchBit_No){ - total_demand++; - } - } - } - - return total_demand; -} - -int Sequencer::getNumberOutstandingPrefetch(){ - int smt_threads = RubyConfig::numberofSMTThreads(); - int total_prefetch = 0; - for(int p=0; p < smt_threads; ++p){ - Vector<Address> keys = m_readRequestTable_ptr[p]->keys(); - for (int i=0; i< keys.size(); i++) { - CacheMsg& request = m_readRequestTable_ptr[p]->lookup(keys[i]); - if(request.getPrefetch() == PrefetchBit_Yes){ - total_prefetch++; - } - } - - keys = m_writeRequestTable_ptr[p]->keys(); - for (int i=0; i< keys.size(); i++) { - CacheMsg& request = m_writeRequestTable_ptr[p]->lookup(keys[i]); - if(request.getPrefetch() == PrefetchBit_Yes){ - total_prefetch++; - } - } - } - - return total_prefetch; -} - -bool Sequencer::isPrefetchRequest(const Address & lineaddr){ - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int p=0; p < smt_threads; ++p){ - // check load requests - Vector<Address> keys = m_readRequestTable_ptr[p]->keys(); - for (int i=0; i< keys.size(); i++) { - CacheMsg& request = m_readRequestTable_ptr[p]->lookup(keys[i]); - if(line_address(request.getAddress()) == lineaddr){ - if(request.getPrefetch() == PrefetchBit_Yes){ - return true; - } - else{ - return false; - } - } - } - - // check store requests - keys = m_writeRequestTable_ptr[p]->keys(); - for (int i=0; i< keys.size(); i++) { - CacheMsg& request = m_writeRequestTable_ptr[p]->lookup(keys[i]); - if(line_address(request.getAddress()) == lineaddr){ - if(request.getPrefetch() == PrefetchBit_Yes){ - return true; - } - else{ - return false; - } - } - } - } - // we should've found a matching request - cout << "isRequestPrefetch() ERROR request NOT FOUND : " << lineaddr << endl; - printProgress(cout); - assert(0); -} - -AccessModeType Sequencer::getAccessModeOfRequest(Address addr, int thread){ - if(m_readRequestTable_ptr[thread]->exist(line_address(addr))){ - CacheMsg& request = m_readRequestTable_ptr[thread]->lookup(addr); - return request.getAccessMode(); - } else if(m_writeRequestTable_ptr[thread]->exist(line_address(addr))){ - CacheMsg& request = m_writeRequestTable_ptr[thread]->lookup(addr); - return request.getAccessMode(); - } else { - printProgress(cout); - ERROR_MSG("Request not found in RequestTables"); - } -} - -Address Sequencer::getLogicalAddressOfRequest(Address addr, int thread){ - assert(thread >= 0); - if(m_readRequestTable_ptr[thread]->exist(line_address(addr))){ - CacheMsg& request = m_readRequestTable_ptr[thread]->lookup(addr); - return request.getLogicalAddress(); - } else if(m_writeRequestTable_ptr[thread]->exist(line_address(addr))){ - CacheMsg& request = m_writeRequestTable_ptr[thread]->lookup(addr); - return request.getLogicalAddress(); - } else { - printProgress(cout); - WARN_MSG("Request not found in RequestTables"); - WARN_MSG(addr); - WARN_MSG(thread); - ASSERT(0); - } -} - -// returns the ThreadID of the request -int Sequencer::getRequestThreadID(const Address & addr){ - int smt_threads = RubyConfig::numberofSMTThreads(); - int thread = -1; - int num_found = 0; - for(int p=0; p < smt_threads; ++p){ - if(m_readRequestTable_ptr[p]->exist(addr)){ - num_found++; - thread = p; - } - if(m_writeRequestTable_ptr[p]->exist(addr)){ - num_found++; - thread = p; - } - } - if(num_found != 1){ - cout << "getRequestThreadID ERROR too many matching requests addr = " << addr << endl; - printProgress(cout); - } - ASSERT(num_found == 1); - ASSERT(thread != -1); - - return thread; -} - -// given a line address, return the request's physical address -Address Sequencer::getRequestPhysicalAddress(const Address & lineaddr){ - int smt_threads = RubyConfig::numberofSMTThreads(); - Address physaddr; - int num_found = 0; - for(int p=0; p < smt_threads; ++p){ - if(m_readRequestTable_ptr[p]->exist(lineaddr)){ - num_found++; - physaddr = (m_readRequestTable_ptr[p]->lookup(lineaddr)).getAddress(); - } - if(m_writeRequestTable_ptr[p]->exist(lineaddr)){ - num_found++; - physaddr = (m_writeRequestTable_ptr[p]->lookup(lineaddr)).getAddress(); - } - } - if(num_found != 1){ - cout << "getRequestPhysicalAddress ERROR too many matching requests addr = " << lineaddr << endl; - printProgress(cout); - } - ASSERT(num_found == 1); - - return physaddr; -} - void Sequencer::printProgress(ostream& out) const{ - + /* int total_demand = 0; out << "Sequencer Stats Version " << m_version << endl; out << "Current time = " << g_eventQueue_ptr->getTime() << endl; out << "---------------" << endl; out << "outstanding requests" << endl; - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int p=0; p < smt_threads; ++p){ - Vector<Address> rkeys = m_readRequestTable_ptr[p]->keys(); - int read_size = rkeys.size(); - out << "proc " << m_chip_ptr->getID() << " thread " << p << " Read Requests = " << read_size << endl; - // print the request table - for(int i=0; i < read_size; ++i){ - CacheMsg & request = m_readRequestTable_ptr[p]->lookup(rkeys[i]); - out << "\tRequest[ " << i << " ] = " << request.getType() << " Address " << rkeys[i] << " Posted " << request.getTime() << " PF " << request.getPrefetch() << endl; - if( request.getPrefetch() == PrefetchBit_No ){ - total_demand++; - } - } - - Vector<Address> wkeys = m_writeRequestTable_ptr[p]->keys(); - int write_size = wkeys.size(); - out << "proc " << m_chip_ptr->getID() << " thread " << p << " Write Requests = " << write_size << endl; - // print the request table - for(int i=0; i < write_size; ++i){ - CacheMsg & request = m_writeRequestTable_ptr[p]->lookup(wkeys[i]); + Vector<Address> rkeys = m_readRequestTable.keys(); + int read_size = rkeys.size(); + out << "proc " << m_version << " Read Requests = " << read_size << endl; + // print the request table + for(int i=0; i < read_size; ++i){ + SequencerRequest * request = m_readRequestTable.lookup(rkeys[i]); + out << "\tRequest[ " << i << " ] = " << request->type << " Address " << rkeys[i] << " Posted " << request->issue_time << " PF " << PrefetchBit_No << endl; + total_demand++; + } + + Vector<Address> wkeys = m_writeRequestTable.keys(); + int write_size = wkeys.size(); + out << "proc " << m_version << " Write Requests = " << write_size << endl; + // print the request table + for(int i=0; i < write_size; ++i){ + CacheMsg & request = m_writeRequestTable.lookup(wkeys[i]); out << "\tRequest[ " << i << " ] = " << request.getType() << " Address " << wkeys[i] << " Posted " << request.getTime() << " PF " << request.getPrefetch() << endl; if( request.getPrefetch() == PrefetchBit_No ){ total_demand++; } - } - - out << endl; } + + out << endl; + out << "Total Number Outstanding: " << m_outstanding_count << endl; out << "Total Number Demand : " << total_demand << endl; out << "Total Number Prefetches : " << m_outstanding_count - total_demand << endl; out << endl; out << endl; - + */ } -void Sequencer::printConfig(ostream& out) { - if (TSO) { - out << "sequencer: Sequencer - TSO" << endl; - } else { - out << "sequencer: Sequencer - SC" << endl; - } - out << " max_outstanding_requests: " << g_SEQUENCER_OUTSTANDING_REQUESTS << endl; -} - -bool Sequencer::empty() const { - return m_outstanding_count == 0; +void Sequencer::printConfig(ostream& out) const { + out << "Seqeuncer config: " << m_name << endl; + out << " controller: " << m_controller->getName() << endl; + out << " version: " << m_version << endl; + out << " max_outstanding_requests: " << m_max_outstanding_requests << endl; + out << " deadlock_threshold: " << m_deadlock_threshold << endl; } // Insert the request on the correct request table. Return true if // the entry was already present. -bool Sequencer::insertRequest(const CacheMsg& request) { - int thread = request.getThreadID(); - assert(thread >= 0); - int total_outstanding = 0; - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int p=0; p < smt_threads; ++p){ - total_outstanding += m_writeRequestTable_ptr[p]->size() + m_readRequestTable_ptr[p]->size(); - } +bool Sequencer::insertRequest(SequencerRequest* request) { + int total_outstanding = m_writeRequestTable.size() + m_readRequestTable.size(); + assert(m_outstanding_count == total_outstanding); // See if we should schedule a deadlock check if (m_deadlock_check_scheduled == false) { - g_eventQueue_ptr->scheduleEvent(this, g_DEADLOCK_THRESHOLD); + g_eventQueue_ptr->scheduleEvent(this, m_deadlock_threshold); m_deadlock_check_scheduled = true; } - if ((request.getType() == CacheRequestType_ST) || - (request.getType() == CacheRequestType_ATOMIC)) { - if (m_writeRequestTable_ptr[thread]->exist(line_address(request.getAddress()))) { - m_writeRequestTable_ptr[thread]->lookup(line_address(request.getAddress())) = request; - return true; + Address line_addr(request->ruby_request.paddr); + line_addr.makeLineAddress(); + if ((request->ruby_request.type == RubyRequestType_ST) || + (request->ruby_request.type == RubyRequestType_RMW)) { + if (m_writeRequestTable.exist(line_addr)) { + m_writeRequestTable.lookup(line_addr) = request; + // return true; + assert(0); // drh5: isn't this an error? do you lose the initial request? } - m_writeRequestTable_ptr[thread]->allocate(line_address(request.getAddress())); - m_writeRequestTable_ptr[thread]->lookup(line_address(request.getAddress())) = request; + m_writeRequestTable.allocate(line_addr); + m_writeRequestTable.lookup(line_addr) = request; m_outstanding_count++; } else { - if (m_readRequestTable_ptr[thread]->exist(line_address(request.getAddress()))) { - m_readRequestTable_ptr[thread]->lookup(line_address(request.getAddress())) = request; - return true; + if (m_readRequestTable.exist(line_addr)) { + m_readRequestTable.lookup(line_addr) = request; + // return true; + assert(0); // drh5: isn't this an error? do you lose the initial request? } - m_readRequestTable_ptr[thread]->allocate(line_address(request.getAddress())); - m_readRequestTable_ptr[thread]->lookup(line_address(request.getAddress())) = request; + m_readRequestTable.allocate(line_addr); + m_readRequestTable.lookup(line_addr) = request; m_outstanding_count++; } g_system_ptr->getProfiler()->sequencerRequests(m_outstanding_count); - total_outstanding = 0; - for(int p=0; p < smt_threads; ++p){ - total_outstanding += m_writeRequestTable_ptr[p]->size() + m_readRequestTable_ptr[p]->size(); - } - + total_outstanding = m_writeRequestTable.size() + m_readRequestTable.size(); assert(m_outstanding_count == total_outstanding); + return false; } -void Sequencer::removeRequest(const CacheMsg& request) { - int thread = request.getThreadID(); - assert(thread >= 0); - int total_outstanding = 0; - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int p=0; p < smt_threads; ++p){ - total_outstanding += m_writeRequestTable_ptr[p]->size() + m_readRequestTable_ptr[p]->size(); - } - assert(m_outstanding_count == total_outstanding); +void Sequencer::removeRequest(SequencerRequest* srequest) { + + assert(m_outstanding_count == m_writeRequestTable.size() + m_readRequestTable.size()); - if ((request.getType() == CacheRequestType_ST) || - (request.getType() == CacheRequestType_ATOMIC)) { - m_writeRequestTable_ptr[thread]->deallocate(line_address(request.getAddress())); + const RubyRequest & ruby_request = srequest->ruby_request; + Address line_addr(ruby_request.paddr); + line_addr.makeLineAddress(); + if ((ruby_request.type == RubyRequestType_ST) || + (ruby_request.type == RubyRequestType_RMW)) { + m_writeRequestTable.deallocate(line_addr); } else { - m_readRequestTable_ptr[thread]->deallocate(line_address(request.getAddress())); + m_readRequestTable.deallocate(line_addr); } m_outstanding_count--; - total_outstanding = 0; - for(int p=0; p < smt_threads; ++p){ - total_outstanding += m_writeRequestTable_ptr[p]->size() + m_readRequestTable_ptr[p]->size(); - } - assert(m_outstanding_count == total_outstanding); -} - -void Sequencer::writeCallback(const Address& address) { - DataBlock data; - writeCallback(address, data); + assert(m_outstanding_count == m_writeRequestTable.size() + m_readRequestTable.size()); } void Sequencer::writeCallback(const Address& address, DataBlock& data) { - // process oldest thread first - int thread = -1; - Time oldest_time = 0; - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int t=0; t < smt_threads; ++t){ - if(m_writeRequestTable_ptr[t]->exist(address)){ - CacheMsg & request = m_writeRequestTable_ptr[t]->lookup(address); - if(thread == -1 || (request.getTime() < oldest_time) ){ - thread = t; - oldest_time = request.getTime(); - } - } - } - // make sure we found an oldest thread - ASSERT(thread != -1); - - CacheMsg & request = m_writeRequestTable_ptr[thread]->lookup(address); - - writeCallback(address, data, GenericMachineType_NULL, PrefetchBit_No, thread); -} - -void Sequencer::writeCallback(const Address& address, DataBlock& data, GenericMachineType respondingMach, PrefetchBit pf, int thread) { assert(address == line_address(address)); - assert(thread >= 0); - assert(m_writeRequestTable_ptr[thread]->exist(line_address(address))); + assert(m_writeRequestTable.exist(line_address(address))); - writeCallback(address, data, respondingMach, thread); - -} - -void Sequencer::writeCallback(const Address& address, DataBlock& data, GenericMachineType respondingMach, int thread) { - assert(address == line_address(address)); - assert(m_writeRequestTable_ptr[thread]->exist(line_address(address))); - CacheMsg request = m_writeRequestTable_ptr[thread]->lookup(address); - assert( request.getThreadID() == thread); + SequencerRequest* request = m_writeRequestTable.lookup(address); removeRequest(request); - assert((request.getType() == CacheRequestType_ST) || - (request.getType() == CacheRequestType_ATOMIC)); - - hitCallback(request, data, respondingMach, thread); + assert((request->ruby_request.type == RubyRequestType_ST) || + (request->ruby_request.type == RubyRequestType_RMW)); -} - -void Sequencer::readCallback(const Address& address) { - DataBlock data; - readCallback(address, data); + hitCallback(request, data); } void Sequencer::readCallback(const Address& address, DataBlock& data) { - // process oldest thread first - int thread = -1; - Time oldest_time = 0; - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int t=0; t < smt_threads; ++t){ - if(m_readRequestTable_ptr[t]->exist(address)){ - CacheMsg & request = m_readRequestTable_ptr[t]->lookup(address); - if(thread == -1 || (request.getTime() < oldest_time) ){ - thread = t; - oldest_time = request.getTime(); - } - } - } - // make sure we found an oldest thread - ASSERT(thread != -1); - - CacheMsg & request = m_readRequestTable_ptr[thread]->lookup(address); - - readCallback(address, data, GenericMachineType_NULL, PrefetchBit_No, thread); -} - -void Sequencer::readCallback(const Address& address, DataBlock& data, GenericMachineType respondingMach, PrefetchBit pf, int thread) { assert(address == line_address(address)); - assert(m_readRequestTable_ptr[thread]->exist(line_address(address))); + assert(m_readRequestTable.exist(line_address(address))); - readCallback(address, data, respondingMach, thread); -} - -void Sequencer::readCallback(const Address& address, DataBlock& data, GenericMachineType respondingMach, int thread) { - assert(address == line_address(address)); - assert(m_readRequestTable_ptr[thread]->exist(line_address(address))); - - CacheMsg request = m_readRequestTable_ptr[thread]->lookup(address); - assert( request.getThreadID() == thread ); + SequencerRequest* request = m_readRequestTable.lookup(address); removeRequest(request); - assert((request.getType() == CacheRequestType_LD) || - (request.getType() == CacheRequestType_IFETCH) - ); + assert((request->ruby_request.type == RubyRequestType_LD) || + (request->ruby_request.type == RubyRequestType_IFETCH)); - hitCallback(request, data, respondingMach, thread); + hitCallback(request, data); } -void Sequencer::hitCallback(const CacheMsg& request, DataBlock& data, GenericMachineType respondingMach, int thread) { - int size = request.getSize(); - Address request_address = request.getAddress(); - Address request_logical_address = request.getLogicalAddress(); - Address request_line_address = line_address(request_address); - CacheRequestType type = request.getType(); - int threadID = request.getThreadID(); - Time issued_time = request.getTime(); - int logical_proc_no = ((m_chip_ptr->getID() * RubyConfig::numberOfProcsPerChip()) + m_version) * RubyConfig::numberofSMTThreads() + threadID; - - DEBUG_MSG(SEQUENCER_COMP, MedPrio, size); +void Sequencer::hitCallback(SequencerRequest* srequest, DataBlock& data) { + const RubyRequest & ruby_request = srequest->ruby_request; + int size = ruby_request.len; + Address request_address(ruby_request.paddr); + Address request_line_address(ruby_request.paddr); + request_line_address.makeLineAddress(); + RubyRequestType type = ruby_request.type; + Time issued_time = srequest->issue_time; // Set this cache entry to the most recently used - if (type == CacheRequestType_IFETCH) { - if (Protocol::m_TwoLevelCache) { - if (m_chip_ptr->m_L1Cache_L1IcacheMemory_vec[m_version]->isTagPresent(request_line_address)) { - m_chip_ptr->m_L1Cache_L1IcacheMemory_vec[m_version]->setMRU(request_line_address); - } - } - else { - if (m_chip_ptr->m_L1Cache_cacheMemory_vec[m_version]->isTagPresent(request_line_address)) { - m_chip_ptr->m_L1Cache_cacheMemory_vec[m_version]->setMRU(request_line_address); - } - } + if (type == RubyRequestType_IFETCH) { + if (m_instCache_ptr->isTagPresent(request_line_address) ) + m_instCache_ptr->setMRU(request_line_address); } else { - if (Protocol::m_TwoLevelCache) { - if (m_chip_ptr->m_L1Cache_L1DcacheMemory_vec[m_version]->isTagPresent(request_line_address)) { - m_chip_ptr->m_L1Cache_L1DcacheMemory_vec[m_version]->setMRU(request_line_address); - } - } - else { - if (m_chip_ptr->m_L1Cache_cacheMemory_vec[m_version]->isTagPresent(request_line_address)) { - m_chip_ptr->m_L1Cache_cacheMemory_vec[m_version]->setMRU(request_line_address); - } - } + if (m_dataCache_ptr->isTagPresent(request_line_address) ) + m_dataCache_ptr->setMRU(request_line_address); } assert(g_eventQueue_ptr->getTime() >= issued_time); Time miss_latency = g_eventQueue_ptr->getTime() - issued_time; - if (PROTOCOL_DEBUG_TRACE) { - g_system_ptr->getProfiler()->profileTransition("Seq", (m_chip_ptr->getID()*RubyConfig::numberOfProcsPerChip()+m_version), -1, request.getAddress(), "", "Done", "", - int_to_string(miss_latency)+" cycles "+GenericMachineType_to_string(respondingMach)+" "+CacheRequestType_to_string(request.getType())+" "+PrefetchBit_to_string(request.getPrefetch())); - } - - DEBUG_MSG(SEQUENCER_COMP, MedPrio, request_address); - DEBUG_MSG(SEQUENCER_COMP, MedPrio, request.getPrefetch()); - if (request.getPrefetch() == PrefetchBit_Yes) { - DEBUG_MSG(SEQUENCER_COMP, MedPrio, "return"); - g_system_ptr->getProfiler()->swPrefetchLatency(miss_latency, type, respondingMach); - return; // Ignore the software prefetch, don't callback the driver - } - // Profile the miss latency for all non-zero demand misses if (miss_latency != 0) { - g_system_ptr->getProfiler()->missLatency(miss_latency, type, respondingMach); - - } - - bool write = - (type == CacheRequestType_ST) || - (type == CacheRequestType_ATOMIC); + g_system_ptr->getProfiler()->missLatency(miss_latency, type); - if (TSO && write) { - m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->callBack(line_address(request.getAddress()), data, - m_packetTable_ptr->lookup(request.getAddress())); - } else { - - // Copy the correct bytes out of the cache line into the subblock - SubBlock subblock(request_address, request_logical_address, size); - subblock.mergeFrom(data); // copy the correct bytes from DataBlock in the SubBlock - - // Scan the store buffer to see if there are any outstanding stores we need to collect - if (TSO) { - m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->updateSubBlock(subblock); + if (Debug::getProtocolTrace()) { + g_system_ptr->getProfiler()->profileTransition("Seq", m_version, Address(ruby_request.paddr), + "", "Done", "", int_to_string(miss_latency)+" cycles"); } + } + /* + if (request.getPrefetch() == PrefetchBit_Yes) { + return; // Ignore the prefetch + } + */ - // Call into the Driver and let it read and/or modify the sub-block - Packet* pkt = m_packetTable_ptr->lookup(request.getAddress()); - - // update data if this is a store/atomic - - /* - if (pkt->req->isCondSwap()) { - L1Cache_Entry entry = m_L1Cache_vec[m_version]->lookup(Address(pkt->req->physAddr())); - DataBlk datablk = entry->getDataBlk(); - uint8_t *orig_data = datablk.getArray(); - if ( datablk.equal(pkt->req->getExtraData()) ) - datablk->setArray(pkt->getData()); - pkt->setData(orig_data); - } - */ - - g_system_ptr->getDriver()->hitCallback(pkt); - m_packetTable_ptr->remove(request.getAddress()); - - // If the request was a Store or Atomic, apply the changes in the SubBlock to the DataBlock - // (This is only triggered for the non-TSO case) - if (write) { - assert(!TSO); - subblock.mergeTo(data); // copy the correct bytes from SubBlock into the DataBlock + // update the data + if (ruby_request.data != NULL) { + if ((type == RubyRequestType_LD) || + (type == RubyRequestType_IFETCH)) { + memcpy(ruby_request.data, data.getData(request_address.getOffset(), ruby_request.len), ruby_request.len); + } else { + data.setData(ruby_request.data, request_address.getOffset(), ruby_request.len); } } -} -void Sequencer::printDebug(){ - //notify driver of debug - g_system_ptr->getDriver()->printDebug(); + m_hit_callback(srequest->id); + delete srequest; } -//dsm: breaks build, delayed // Returns true if the sequencer already has a load or store outstanding -bool -Sequencer::isReady(const Packet* pkt) const -{ - - int cpu_number = pkt->req->contextId(); - la_t logical_addr = pkt->req->getVaddr(); - pa_t physical_addr = pkt->req->getPaddr(); - CacheRequestType type_of_request; - if ( pkt->req->isInstFetch() ) { - type_of_request = CacheRequestType_IFETCH; - } else if ( pkt->req->isLocked() || pkt->req->isSwap() ) { - type_of_request = CacheRequestType_ATOMIC; - } else if ( pkt->isRead() ) { - type_of_request = CacheRequestType_LD; - } else if ( pkt->isWrite() ) { - type_of_request = CacheRequestType_ST; - } else { - assert(false); +bool Sequencer::isReady(const RubyRequest& request) const { + // POLINA: check if we are currently flushing the write buffer, if so Ruby is returned as not ready + // to simulate stalling of the front-end + // Do we stall all the sequencers? If it is atomic instruction - yes! + if (m_outstanding_count >= m_max_outstanding_requests) { + return false; } - int thread = pkt->req->threadId(); - - CacheMsg request(Address( physical_addr ), - Address( physical_addr ), - type_of_request, - Address(0), - AccessModeType_UserMode, // User/supervisor mode - 0, // Size in bytes of request - PrefetchBit_No, // Not a prefetch - 0, // Version number - Address(logical_addr), // Virtual Address - thread // SMT thread - ); - return isReady(request); -} -bool -Sequencer::isReady(const CacheMsg& request) const -{ - if (m_outstanding_count >= g_SEQUENCER_OUTSTANDING_REQUESTS) { - //cout << "TOO MANY OUTSTANDING: " << m_outstanding_count << " " << g_SEQUENCER_OUTSTANDING_REQUESTS << " VER " << m_version << endl; + if( m_writeRequestTable.exist(line_address(Address(request.paddr))) || + m_readRequestTable.exist(line_address(Address(request.paddr))) ){ + //cout << "OUTSTANDING REQUEST EXISTS " << p << " VER " << m_version << endl; //printProgress(cout); return false; } - // This code allows reads to be performed even when we have a write - // request outstanding for the line - bool write = - (request.getType() == CacheRequestType_ST) || - (request.getType() == CacheRequestType_ATOMIC); - - // LUKE - disallow more than one request type per address - // INVARIANT: at most one request type per address, per processor - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int p=0; p < smt_threads; ++p){ - if( m_writeRequestTable_ptr[p]->exist(line_address(request.getAddress())) || - m_readRequestTable_ptr[p]->exist(line_address(request.getAddress())) ){ - //cout << "OUTSTANDING REQUEST EXISTS " << p << " VER " << m_version << endl; - //printProgress(cout); - return false; - } - } - - if (TSO) { - return m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->isReady(); - } return true; } -//dsm: breaks build, delayed -// Called by Driver (Simics or Tester). -void -Sequencer::makeRequest(Packet* pkt) -{ - int cpu_number = pkt->req->contextId(); - la_t logical_addr = pkt->req->getVaddr(); - pa_t physical_addr = pkt->req->getPaddr(); - int request_size = pkt->getSize(); - CacheRequestType type_of_request; - PrefetchBit prefetch; - bool write = false; - if ( pkt->req->isInstFetch() ) { - type_of_request = CacheRequestType_IFETCH; - } else if ( pkt->req->isLocked() || pkt->req->isSwap() ) { - type_of_request = CacheRequestType_ATOMIC; - write = true; - } else if ( pkt->isRead() ) { - type_of_request = CacheRequestType_LD; - } else if ( pkt->isWrite() ) { - type_of_request = CacheRequestType_ST; - write = true; - } else { - assert(false); - } - if (pkt->req->isPrefetch()) { - prefetch = PrefetchBit_Yes; - } else { - prefetch = PrefetchBit_No; - } - la_t virtual_pc = pkt->req->getPC(); - int isPriv = false; // TODO: get permission data - int thread = pkt->req->threadId(); - - AccessModeType access_mode = AccessModeType_UserMode; // TODO: get actual permission - - CacheMsg request(Address( physical_addr ), - Address( physical_addr ), - type_of_request, - Address(virtual_pc), - access_mode, // User/supervisor mode - request_size, // Size in bytes of request - prefetch, - 0, // Version number - Address(logical_addr), // Virtual Address - thread // SMT thread - ); - - if ( TSO && write && !pkt->req->isPrefetch() ) { - assert(m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->isReady()); - m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->insertStore(pkt, request); - return; - } - - m_packetTable_ptr->insert(Address( physical_addr ), pkt); - - doRequest(request); -} - -bool Sequencer::doRequest(const CacheMsg& request) { - bool hit = false; - // Check the fast path - DataBlock* data_ptr; - - int thread = request.getThreadID(); - - hit = tryCacheAccess(line_address(request.getAddress()), - request.getType(), - request.getProgramCounter(), - request.getAccessMode(), - request.getSize(), - data_ptr); - - if (hit && (request.getType() == CacheRequestType_IFETCH || !REMOVE_SINGLE_CYCLE_DCACHE_FAST_PATH) ) { - DEBUG_MSG(SEQUENCER_COMP, MedPrio, "Fast path hit"); - hitCallback(request, *data_ptr, GenericMachineType_L1Cache, thread); - return true; - } - - if (TSO && (request.getType() == CacheRequestType_LD || request.getType() == CacheRequestType_IFETCH)) { - - // See if we can satisfy the load entirely from the store buffer - SubBlock subblock(line_address(request.getAddress()), request.getSize()); - if (m_chip_ptr->m_L1Cache_storeBuffer_vec[m_version]->trySubBlock(subblock)) { - DataBlock dummy; - hitCallback(request, dummy, GenericMachineType_NULL, thread); // Call with an 'empty' datablock, since the data is in the store buffer - return true; - } - } - - DEBUG_MSG(SEQUENCER_COMP, MedPrio, "Fast path miss"); - issueRequest(request); - return hit; +bool Sequencer::empty() const { + return (m_writeRequestTable.size() == 0) && (m_readRequestTable.size() == 0); } -void Sequencer::issueRequest(const CacheMsg& request) { - bool found = insertRequest(request); - - if (!found) { - CacheMsg msg = request; - msg.getAddress() = line_address(request.getAddress()); // Make line address - - // Fast Path L1 misses are profiled here - all non-fast path misses are profiled within the generated protocol code - if (!REMOVE_SINGLE_CYCLE_DCACHE_FAST_PATH) { - g_system_ptr->getProfiler()->addPrimaryStatSample(msg, m_chip_ptr->getID()); - } - - if (PROTOCOL_DEBUG_TRACE) { - g_system_ptr->getProfiler()->profileTransition("Seq", (m_chip_ptr->getID()*RubyConfig::numberOfProcsPerChip() + m_version), -1, msg.getAddress(),"", "Begin", "", CacheRequestType_to_string(request.getType())); - } - -#if 0 - // Commented out by nate binkert because I removed the trace stuff - if (g_system_ptr->getTracer()->traceEnabled()) { - g_system_ptr->getTracer()->traceRequest((m_chip_ptr->getID()*RubyConfig::numberOfProcsPerChip()+m_version), msg.getAddress(), msg.getProgramCounter(), - msg.getType(), g_eventQueue_ptr->getTime()); - } -#endif - - Time latency = 0; // initialzed to an null value - - latency = SEQUENCER_TO_CONTROLLER_LATENCY; - - // Send the message to the cache controller - assert(latency > 0); - m_chip_ptr->m_L1Cache_mandatoryQueue_vec[m_version]->enqueue(msg, latency); - - } // !found +int64_t Sequencer::makeRequest(const RubyRequest & request) +{ + assert(Address(request.paddr).getOffset() + request.len <= RubySystem::getBlockSizeBytes()); + if (isReady(request)) { + int64_t id = makeUniqueRequestID(); + SequencerRequest *srequest = new SequencerRequest(request, id, g_eventQueue_ptr->getTime()); + bool found = insertRequest(srequest); + if (!found) + issueRequest(request); + + // TODO: issue hardware prefetches here + return id; + } + else { + return -1; + } +} + +void Sequencer::issueRequest(const RubyRequest& request) { + + // TODO: get rid of CacheMsg, CacheRequestType, and AccessModeTYpe, & have SLICC use RubyRequest and subtypes natively + CacheRequestType ctype; + switch(request.type) { + case RubyRequestType_IFETCH: + ctype = CacheRequestType_IFETCH; + break; + case RubyRequestType_LD: + ctype = CacheRequestType_LD; + break; + case RubyRequestType_ST: + ctype = CacheRequestType_ST; + break; + case RubyRequestType_RMW: + ctype = CacheRequestType_ATOMIC; + break; + default: + assert(0); + } + AccessModeType amtype; + switch(request.access_mode){ + case RubyAccessMode_User: + amtype = AccessModeType_UserMode; + break; + case RubyAccessMode_Supervisor: + amtype = AccessModeType_SupervisorMode; + break; + case RubyAccessMode_Device: + amtype = AccessModeType_UserMode; + break; + default: + assert(0); + } + Address line_addr(request.paddr); + line_addr.makeLineAddress(); + CacheMsg msg(line_addr, Address(request.paddr), ctype, Address(request.pc), amtype, request.len, PrefetchBit_No); + + if (Debug::getProtocolTrace()) { + g_system_ptr->getProfiler()->profileTransition("Seq", m_version, Address(request.paddr), + "", "Begin", "", RubyRequestType_to_string(request.type)); + } + + if (g_system_ptr->getTracer()->traceEnabled()) { + g_system_ptr->getTracer()->traceRequest(m_name, line_addr, Address(request.pc), + request.type, g_eventQueue_ptr->getTime()); + } + + Time latency = 0; // initialzed to an null value + + if (request.type == RubyRequestType_IFETCH) + latency = m_instCache_ptr->getLatency(); + else + latency = m_dataCache_ptr->getLatency(); + + // Send the message to the cache controller + assert(latency > 0); + + + m_mandatory_q_ptr->enqueue(msg, latency); } - +/* bool Sequencer::tryCacheAccess(const Address& addr, CacheRequestType type, - const Address& pc, AccessModeType access_mode, + AccessModeType access_mode, int size, DataBlock*& data_ptr) { if (type == CacheRequestType_IFETCH) { - if (Protocol::m_TwoLevelCache) { - return m_chip_ptr->m_L1Cache_L1IcacheMemory_vec[m_version]->tryCacheAccess(line_address(addr), type, data_ptr); - } - else { - return m_chip_ptr->m_L1Cache_cacheMemory_vec[m_version]->tryCacheAccess(line_address(addr), type, data_ptr); - } + return m_instCache_ptr->tryCacheAccess(line_address(addr), type, data_ptr); } else { - if (Protocol::m_TwoLevelCache) { - return m_chip_ptr->m_L1Cache_L1DcacheMemory_vec[m_version]->tryCacheAccess(line_address(addr), type, data_ptr); - } - else { - return m_chip_ptr->m_L1Cache_cacheMemory_vec[m_version]->tryCacheAccess(line_address(addr), type, data_ptr); - } - } -} - -void Sequencer::resetRequestTime(const Address& addr, int thread){ - assert(thread >= 0); - //reset both load and store requests, if they exist - if(m_readRequestTable_ptr[thread]->exist(line_address(addr))){ - CacheMsg& request = m_readRequestTable_ptr[thread]->lookup(addr); - if( request.m_AccessMode != AccessModeType_UserMode){ - cout << "resetRequestType ERROR read request addr = " << addr << " thread = "<< thread << " is SUPERVISOR MODE" << endl; - printProgress(cout); - } - //ASSERT(request.m_AccessMode == AccessModeType_UserMode); - request.setTime(g_eventQueue_ptr->getTime()); + return m_dataCache_ptr->tryCacheAccess(line_address(addr), type, data_ptr); } - if(m_writeRequestTable_ptr[thread]->exist(line_address(addr))){ - CacheMsg& request = m_writeRequestTable_ptr[thread]->lookup(addr); - if( request.m_AccessMode != AccessModeType_UserMode){ - cout << "resetRequestType ERROR write request addr = " << addr << " thread = "<< thread << " is SUPERVISOR MODE" << endl; - printProgress(cout); - } - //ASSERT(request.m_AccessMode == AccessModeType_UserMode); - request.setTime(g_eventQueue_ptr->getTime()); - } -} - -// removes load request from queue -void Sequencer::removeLoadRequest(const Address & addr, int thread){ - removeRequest(getReadRequest(addr, thread)); -} - -void Sequencer::removeStoreRequest(const Address & addr, int thread){ - removeRequest(getWriteRequest(addr, thread)); -} - -// returns the read CacheMsg -CacheMsg & Sequencer::getReadRequest( const Address & addr, int thread ){ - Address temp = addr; - assert(thread >= 0); - assert(temp == line_address(temp)); - assert(m_readRequestTable_ptr[thread]->exist(addr)); - return m_readRequestTable_ptr[thread]->lookup(addr); -} - -CacheMsg & Sequencer::getWriteRequest( const Address & addr, int thread){ - Address temp = addr; - assert(thread >= 0); - assert(temp == line_address(temp)); - assert(m_writeRequestTable_ptr[thread]->exist(addr)); - return m_writeRequestTable_ptr[thread]->lookup(addr); } +*/ void Sequencer::print(ostream& out) const { - out << "[Sequencer: " << m_chip_ptr->getID() + out << "[Sequencer: " << m_version << ", outstanding requests: " << m_outstanding_count; - int smt_threads = RubyConfig::numberofSMTThreads(); - for(int p=0; p < smt_threads; ++p){ - out << ", read request table[ " << p << " ]: " << *m_readRequestTable_ptr[p] - << ", write request table[ " << p << " ]: " << *m_writeRequestTable_ptr[p]; - } + out << ", read request table: " << m_readRequestTable + << ", write request table: " << m_writeRequestTable; out << "]"; } @@ -941,20 +456,183 @@ void Sequencer::checkCoherence(const Address& addr) { #endif } +/* bool Sequencer::getRubyMemoryValue(const Address& addr, char* value, - unsigned int size_in_bytes ) { - for(unsigned int i=0; i < size_in_bytes; i++) { - std::cerr << __FILE__ << "(" << __LINE__ << "): Not implemented. " << std::endl; - value[i] = 0; // _read_physical_memory( m_chip_ptr->getID()*RubyConfig::numberOfProcsPerChip()+m_version, - // addr.getAddress() + i, 1 ); - } - return false; // Do nothing? + unsigned int size_in_bytes ) +{ + bool found = false; + const Address lineAddr = line_address(addr); + DataBlock data; + PhysAddress paddr(addr); + DataBlock* dataPtr = &data; + + MachineID l2_mach = map_L2ChipId_to_L2Cache(addr, m_chip_ptr->getID() ); + int l2_ver = l2_mach.num%RubyConfig::numberOfL2CachePerChip(); + + if (Protocol::m_TwoLevelCache) { + if(Protocol::m_CMP){ + assert(n->m_L2Cache_L2cacheMemory_vec[l2_ver] != NULL); + } + else{ + assert(n->m_L1Cache_cacheMemory_vec[m_version] != NULL); + } + } + + if (n->m_L1Cache_L1IcacheMemory_vec[m_version]->tryCacheAccess(lineAddr, CacheRequestType_IFETCH, dataPtr)){ + n->m_L1Cache_L1IcacheMemory_vec[m_version]->getMemoryValue(addr, value, size_in_bytes); + found = true; + } else if (n->m_L1Cache_L1DcacheMemory_vec[m_version]->tryCacheAccess(lineAddr, CacheRequestType_LD, dataPtr)){ + n->m_L1Cache_L1DcacheMemory_vec[m_version]->getMemoryValue(addr, value, size_in_bytes); + found = true; + } else if (Protocol::m_CMP && n->m_L2Cache_L2cacheMemory_vec[l2_ver]->tryCacheAccess(lineAddr, CacheRequestType_LD, dataPtr)){ + n->m_L2Cache_L2cacheMemory_vec[l2_ver]->getMemoryValue(addr, value, size_in_bytes); + found = true; + // } else if (n->TBE_TABLE_MEMBER_VARIABLE->isPresent(lineAddr)){ +// ASSERT(n->TBE_TABLE_MEMBER_VARIABLE->isPresent(lineAddr)); +// L1Cache_TBE tbeEntry = n->TBE_TABLE_MEMBER_VARIABLE->lookup(lineAddr); + +// int offset = addr.getOffset(); +// for(int i=0; i<size_in_bytes; ++i){ +// value[i] = tbeEntry.getDataBlk().getByte(offset + i); +// } + +// found = true; + } else { + // Address not found + //cout << " " << m_chip_ptr->getID() << " NOT IN CACHE, Value at Directory is: " << (int) value[0] << endl; + n = dynamic_cast<Chip*>(g_system_ptr->getChip(map_Address_to_DirectoryNode(addr)/RubyConfig::numberOfDirectoryPerChip())); + int dir_version = map_Address_to_DirectoryNode(addr)%RubyConfig::numberOfDirectoryPerChip(); + for(unsigned int i=0; i<size_in_bytes; ++i){ + int offset = addr.getOffset(); + value[i] = n->m_Directory_directory_vec[dir_version]->lookup(lineAddr).m_DataBlk.getByte(offset + i); + } + // Address not found + //WARN_MSG("Couldn't find address"); + //WARN_EXPR(addr); + found = false; + } + return true; } bool Sequencer::setRubyMemoryValue(const Address& addr, char *value, unsigned int size_in_bytes) { char test_buffer[64]; - return false; // Do nothing? + // idea here is that coherent cache should find the + // latest data, the update it + bool found = false; + const Address lineAddr = line_address(addr); + PhysAddress paddr(addr); + DataBlock data; + DataBlock* dataPtr = &data; + Chip* n = dynamic_cast<Chip*>(m_chip_ptr); + + MachineID l2_mach = map_L2ChipId_to_L2Cache(addr, m_chip_ptr->getID() ); + int l2_ver = l2_mach.num%RubyConfig::numberOfL2CachePerChip(); + + assert(n->m_L1Cache_L1IcacheMemory_vec[m_version] != NULL); + assert(n->m_L1Cache_L1DcacheMemory_vec[m_version] != NULL); + if (Protocol::m_TwoLevelCache) { + if(Protocol::m_CMP){ + assert(n->m_L2Cache_L2cacheMemory_vec[l2_ver] != NULL); + } + else{ + assert(n->m_L1Cache_cacheMemory_vec[m_version] != NULL); + } + } + + if (n->m_L1Cache_L1IcacheMemory_vec[m_version]->tryCacheAccess(lineAddr, CacheRequestType_IFETCH, dataPtr)){ + n->m_L1Cache_L1IcacheMemory_vec[m_version]->setMemoryValue(addr, value, size_in_bytes); + found = true; + } else if (n->m_L1Cache_L1DcacheMemory_vec[m_version]->tryCacheAccess(lineAddr, CacheRequestType_LD, dataPtr)){ + n->m_L1Cache_L1DcacheMemory_vec[m_version]->setMemoryValue(addr, value, size_in_bytes); + found = true; + } else if (Protocol::m_CMP && n->m_L2Cache_L2cacheMemory_vec[l2_ver]->tryCacheAccess(lineAddr, CacheRequestType_LD, dataPtr)){ + n->m_L2Cache_L2cacheMemory_vec[l2_ver]->setMemoryValue(addr, value, size_in_bytes); + found = true; + } else { + // Address not found + n = dynamic_cast<Chip*>(g_system_ptr->getChip(map_Address_to_DirectoryNode(addr)/RubyConfig::numberOfDirectoryPerChip())); + int dir_version = map_Address_to_DirectoryNode(addr)%RubyConfig::numberOfDirectoryPerChip(); + for(unsigned int i=0; i<size_in_bytes; ++i){ + int offset = addr.getOffset(); + n->m_Directory_directory_vec[dir_version]->lookup(lineAddr).m_DataBlk.setByte(offset + i, value[i]); + } + found = false; + } + + if (found){ + found = getRubyMemoryValue(addr, test_buffer, size_in_bytes); + assert(found); + if(value[0] != test_buffer[0]){ + WARN_EXPR((int) value[0]); + WARN_EXPR((int) test_buffer[0]); + ERROR_MSG("setRubyMemoryValue failed to set value."); + } + } + + return true; +} +*/ +/* + +void +Sequencer::rubyMemAccess(const uint64 paddr, char* data, const int len, const AccessType type) +{ + if ( type == AccessType_Read || type == AccessType_Write ) { + // need to break up the packet data + uint64 guest_ptr = paddr; + Vector<DataBlock*> datablocks; + while (paddr + len != guest_ptr) { + Address addr(guest_ptr); + Address line_addr = line_address(addr); + + int bytes_copied; + if (addr.getOffset() == 0) { + bytes_copied = (guest_ptr + RubyConfig::dataBlockBytes() > paddr + len)? + (paddr + len - guest_ptr): + RubyConfig::dataBlockBytes(); + } else { + bytes_copied = RubyConfig::dataBlockBytes() - addr.getOffset(); + if (guest_ptr + bytes_copied > paddr + len) + bytes_copied = paddr + len - guest_ptr; + } + + // first we need to find all data blocks that have to be updated for a write + // and the highest block for a read + for(int i=0;i<RubyConfig::numberOfProcessors();i++) { + if (Protocol::m_TwoLevelCache){ + if(m_chip_ptr->m_L1Cache_L1IcacheMemory_vec[i]->isTagPresent(line_address(addr))) + datablocks.insertAtBottom(&m_chip_ptr->m_L1Cache_L1IcacheMemory_vec[i]->lookup(line_addr).getDataBlk()); + if(m_chip_ptr->m_L1Cache_L1DcacheMemory_vec[i]->isTagPresent(line_address(addr))) + datablocks.insertAtBottom(&m_chip_ptr->m_L1Cache_L1DcacheMemory_vec[i]->lookup(line_addr).getDataBlk()); + } else { + if(m_chip_ptr->m_L1Cache_cacheMemory_vec[i]->isTagPresent(line_address(addr))) + datablocks.insertAtBottom(&m_chip_ptr->m_L1Cache_cacheMemory_vec[i]->lookup(line_addr).getDataBlk()); + } + } + if (Protocol::m_TwoLevelCache){ + int l2_bank = map_L2ChipId_to_L2Cache(addr, 0).num; // TODO: ONLY WORKS WITH CMP!!! + if (m_chip_ptr->m_L2Cache_L2cacheMemory_vec[l2_bank]->isTagPresent(line_address(Address(paddr)))) { + datablocks.insertAtBottom(&m_chip_ptr->m_L2Cache_L2cacheMemory_vec[l2_bank]->lookup(addr).getDataBlk()); + } + } + assert(dynamic_cast<Chip*>(m_chip_ptr)->m_Directory_directory_vec.size() > map_Address_to_DirectoryNode(addr)); + DirectoryMemory* dir = dynamic_cast<Chip*>(m_chip_ptr)->m_Directory_directory_vec[map_Address_to_DirectoryNode(addr)]; + Directory_Entry& entry = dir->lookup(line_addr); + datablocks.insertAtBottom(&entry.getDataBlk()); + + if (pkt->isRead()){ + datablocks[0]->copyData(pkt_data, addr.getOffset(), bytes_copied); + } else {// pkt->isWrite() { + for (int i=0;i<datablocks.size();i++) + datablocks[i]->setData(pkt_data, addr.getOffset(), bytes_copied); + } + + guest_ptr += bytes_copied; + pkt_data += bytes_copied; + datablocks.clear(); + } } +*/ diff --git a/src/mem/ruby/system/Sequencer.hh b/src/mem/ruby/system/Sequencer.hh index 1ccfd97ce..254f5a092 100644 --- a/src/mem/ruby/system/Sequencer.hh +++ b/src/mem/ruby/system/Sequencer.hh @@ -44,19 +44,31 @@ #include "mem/protocol/AccessModeType.hh" #include "mem/protocol/GenericMachineType.hh" #include "mem/protocol/PrefetchBit.hh" +#include "mem/ruby/system/RubyPort.hh" #include "mem/gems_common/Map.hh" +#include "mem/ruby/common/Address.hh" class DataBlock; -class AbstractChip; class CacheMsg; -class Address; class MachineID; -class Packet; +class CacheMemory; +class AbstractController; -class Sequencer : public Consumer { +struct SequencerRequest { + RubyRequest ruby_request; + int64_t id; + Time issue_time; + + SequencerRequest(const RubyRequest & _ruby_request, int64_t _id, Time _issue_time) + : ruby_request(_ruby_request), id(_id), issue_time(_issue_time) + {} +}; + +class Sequencer : public Consumer, public RubyPort { public: // Constructors - Sequencer(AbstractChip* chip_ptr, int version); + Sequencer(const string & name); + void init(const vector<string> & argv); // Destructor ~Sequencer(); @@ -64,87 +76,53 @@ public: // Public Methods void wakeup(); // Used only for deadlock detection - static void printConfig(ostream& out); - - // returns total number of outstanding request (includes prefetches) - int getNumberOutstanding(); - // return only total number of outstanding demand requests - int getNumberOutstandingDemand(); - // return only total number of outstanding prefetch requests - int getNumberOutstandingPrefetch(); - - // remove load/store request from queue - void removeLoadRequest(const Address & addr, int thread); - void removeStoreRequest(const Address & addr, int thread); + void printConfig(ostream& out) const; void printProgress(ostream& out) const; - // returns a pointer to the request in the request tables - CacheMsg & getReadRequest( const Address & addr, int thread ); - CacheMsg & getWriteRequest( const Address & addr, int thread ); - void writeCallback(const Address& address, DataBlock& data); void readCallback(const Address& address, DataBlock& data); - void writeCallback(const Address& address); - void readCallback(const Address& address); - void writeCallback(const Address& address, DataBlock& data, GenericMachineType respondingMach, PrefetchBit pf, int thread); - void readCallback(const Address& address, DataBlock& data, GenericMachineType respondingMach, PrefetchBit pf, int thread); - void writeCallback(const Address& address, DataBlock& data, GenericMachineType respondingMach, int thread); - void readCallback(const Address& address, DataBlock& data, GenericMachineType respondingMach, int thread); - - // returns the thread ID of the request - int getRequestThreadID(const Address & addr); - // returns the physical address of the request - Address getRequestPhysicalAddress(const Address & lineaddr); - // returns whether a request is a prefetch request - bool isPrefetchRequest(const Address & lineaddr); - - //notifies driver of debug print - void printDebug(); // called by Tester or Simics - void makeRequest(Packet* pkt); - bool doRequest(const CacheMsg& request); - void issueRequest(const CacheMsg& request); - bool isReady(const Packet* pkt) const; - bool isReady(const CacheMsg& request) const; // depricate this function + int64_t makeRequest(const RubyRequest & request); + bool isReady(const RubyRequest& request) const; bool empty() const; - void resetRequestTime(const Address& addr, int thread); - Address getLogicalAddressOfRequest(Address address, int thread); - AccessModeType getAccessModeOfRequest(Address address, int thread); - //uint64 getSequenceNumberOfRequest(Address addr, int thread); void print(ostream& out) const; void checkCoherence(const Address& address); - bool getRubyMemoryValue(const Address& addr, char* value, unsigned int size_in_bytes); - bool setRubyMemoryValue(const Address& addr, char *value, unsigned int size_in_bytes); + // bool getRubyMemoryValue(const Address& addr, char* value, unsigned int size_in_bytes); + // bool setRubyMemoryValue(const Address& addr, char *value, unsigned int size_in_bytes); - void removeRequest(const CacheMsg& request); + void removeRequest(SequencerRequest* request); private: // Private Methods bool tryCacheAccess(const Address& addr, CacheRequestType type, const Address& pc, AccessModeType access_mode, int size, DataBlock*& data_ptr); - // void conflictCallback(const CacheMsg& request, GenericMachineType respondingMach, int thread); - void hitCallback(const CacheMsg& request, DataBlock& data, GenericMachineType respondingMach, int thread); - bool insertRequest(const CacheMsg& request); + void issueRequest(const RubyRequest& request); + + void hitCallback(SequencerRequest* request, DataBlock& data); + bool insertRequest(SequencerRequest* request); // Private copy constructor and assignment operator Sequencer(const Sequencer& obj); Sequencer& operator=(const Sequencer& obj); - // Data Members (m_ prefix) - AbstractChip* m_chip_ptr; +private: + int m_max_outstanding_requests; + int m_deadlock_threshold; + + AbstractController* m_controller; + MessageBuffer* m_mandatory_q_ptr; + CacheMemory* m_dataCache_ptr; + CacheMemory* m_instCache_ptr; // indicates what processor on the chip this sequencer is associated with int m_version; + int m_controller_type; - // One request table per SMT thread - Map<Address, CacheMsg>** m_writeRequestTable_ptr; - Map<Address, CacheMsg>** m_readRequestTable_ptr; - - Map<Address, Packet*>* m_packetTable_ptr; - + Map<Address, SequencerRequest*> m_writeRequestTable; + Map<Address, SequencerRequest*> m_readRequestTable; // Global outstanding request count, across all request tables int m_outstanding_count; bool m_deadlock_check_scheduled; diff --git a/src/mem/ruby/system/StoreBuffer.cc b/src/mem/ruby/system/StoreBuffer.cc deleted file mode 100644 index 280decdd8..000000000 --- a/src/mem/ruby/system/StoreBuffer.cc +++ /dev/null @@ -1,302 +0,0 @@ - -/* - * 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. - */ - -/* - * $Id$ - * - */ - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/config/RubyConfig.hh" -#include "mem/ruby/system/StoreBuffer.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" -#include "mem/ruby/system/System.hh" -#include "mem/ruby/common/Driver.hh" -#include "mem/gems_common/Vector.hh" -#include "mem/ruby/eventqueue/RubyEventQueue.hh" -#include "mem/ruby/profiler/AddressProfiler.hh" -#include "mem/ruby/system/Sequencer.hh" -#include "mem/ruby/common/SubBlock.hh" -#include "mem/ruby/profiler/Profiler.hh" -#include "mem/packet.hh" - -// *** Begin Helper class *** -struct StoreBufferEntry { - StoreBufferEntry() {} // So we can allocate a vector of StoreBufferEntries - StoreBufferEntry(const SubBlock& block, CacheRequestType type, const Address& pc, AccessModeType access_mode, int size, int thread) : m_subblock(block) { - m_type = type; - m_pc = pc; - m_access_mode = access_mode; - m_size = size; - m_thread = thread; - m_time = g_eventQueue_ptr->getTime(); - } - - void print(ostream& out) const - { - out << "[StoreBufferEntry: " - << "SubBlock: " << m_subblock - << ", Type: " << m_type - << ", PC: " << m_pc - << ", AccessMode: " << m_access_mode - << ", Size: " << m_size - << ", Thread: " << m_thread - << ", Time: " << m_time - << "]"; - } - - SubBlock m_subblock; - CacheRequestType m_type; - Address m_pc; - AccessModeType m_access_mode; - int m_size; - int m_thread; - Time m_time; -}; - -extern inline -ostream& operator<<(ostream& out, const StoreBufferEntry& obj) -{ - obj.print(out); - out << flush; - return out; -} - -// *** End Helper class *** - -const int MAX_ENTRIES = 128; - -static void inc_index(int& index) -{ - index++; - if (index >= MAX_ENTRIES) { - index = 0; - } -} - -StoreBuffer::StoreBuffer(AbstractChip* chip_ptr, int version) : - m_store_cache() -{ - m_chip_ptr = chip_ptr; - m_version = version; - m_queue_ptr = new Vector<StoreBufferEntry>(MAX_ENTRIES); - m_queue_ptr->setSize(MAX_ENTRIES); - m_pending = false; - m_seen_atomic = false; - m_head = 0; - m_tail = 0; - m_size = 0; - m_deadlock_check_scheduled = false; -} - -StoreBuffer::~StoreBuffer() -{ - delete m_queue_ptr; -} - -// Used only to check for deadlock -void StoreBuffer::wakeup() -{ - // Check for deadlock of any of the requests - Time current_time = g_eventQueue_ptr->getTime(); - - int queue_pointer = m_head; - for (int i=0; i<m_size; i++) { - if (current_time - (getEntry(queue_pointer).m_time) >= g_DEADLOCK_THRESHOLD) { - WARN_EXPR(getEntry(queue_pointer)); - WARN_EXPR(m_chip_ptr->getID()); - WARN_EXPR(current_time); - ERROR_MSG("Possible Deadlock detected"); - } - inc_index(queue_pointer); - } - - if (m_size > 0) { // If there are still outstanding requests, keep checking - g_eventQueue_ptr->scheduleEvent(this, g_DEADLOCK_THRESHOLD); - } else { - m_deadlock_check_scheduled = false; - } -} - -void StoreBuffer::printConfig(ostream& out) -{ - out << "Store buffer entries: " << MAX_ENTRIES << " (Only valid if TSO is enabled)" << endl; -} - -// Handle an incoming store request, this method is responsible for -// calling hitCallback as needed -void -StoreBuffer::insertStore(Packet* pkt, const CacheMsg& request) -{ - Address addr = request.getAddress(); - CacheRequestType type = request.getType(); - Address pc = request.getProgramCounter(); - AccessModeType access_mode = request.getAccessMode(); - int size = request.getSize(); - int threadID = request.getThreadID(); - - DEBUG_MSG(STOREBUFFER_COMP, MedPrio, "insertStore"); - DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, g_eventQueue_ptr->getTime()); - assert((type == CacheRequestType_ST) || (type == CacheRequestType_ATOMIC)); - assert(isReady()); - - // See if we should schedule a deadlock check - if (m_deadlock_check_scheduled == false) { - g_eventQueue_ptr->scheduleEvent(this, g_DEADLOCK_THRESHOLD); - m_deadlock_check_scheduled = true; - } - - // Perform the hit-callback for the store - SubBlock subblock(addr, size); - if(type == CacheRequestType_ST) { - g_system_ptr->getDriver()->hitCallback(pkt); - assert(subblock.getSize() != 0); - } else { - // wait to perform the hitCallback until later for Atomics - } - - // Perform possible pre-fetch - if(!isEmpty()) { - Packet new_pkt(pkt); - pkt->req->setFlags(Request::PREFETCH); - m_chip_ptr->getSequencer(m_version)->makeRequest(&new_pkt); - } - - // Update the StoreCache - m_store_cache.add(subblock); - - // Enqueue the entry - StoreBufferEntry entry(subblock, type, pc, access_mode, size, threadID); // FIXME - enqueue(entry); - - if(type == CacheRequestType_ATOMIC) { - m_seen_atomic = true; - } - - processHeadOfQueue(); -} - -void StoreBuffer::callBack(const Address& addr, DataBlock& data, Packet* pkt) -{ - DEBUG_MSG(STOREBUFFER_COMP, MedPrio, "callBack"); - DEBUG_EXPR(STOREBUFFER_COMP, MedPrio, g_eventQueue_ptr->getTime()); - assert(!isEmpty()); - assert(m_pending == true); - assert(line_address(addr) == addr); - assert(line_address(m_pending_address) == addr); - assert(line_address(peek().m_subblock.getAddress()) == addr); - CacheRequestType type = peek().m_type; - //int threadID = peek().m_thread; - assert((type == CacheRequestType_ST) || (type == CacheRequestType_ATOMIC)); - m_pending = false; - - // If oldest entry was ATOMIC, perform the callback - if(type == CacheRequestType_ST) { - // We already performed the call back for the store at insert time - } else { - // We waited to perform the hitCallback until now for Atomics - peek().m_subblock.mergeFrom(data); // copy the correct bytes from DataBlock into the SubBlock for the Load part of the atomic Load/Store - g_system_ptr->getDriver()->hitCallback(pkt); - m_seen_atomic = false; - - /// FIXME - record the time spent in the store buffer - split out ST vs ATOMIC - } - assert(peek().m_subblock.getSize() != 0); - - // Apply the head entry to the datablock - peek().m_subblock.mergeTo(data); // For both the Store and Atomic cases - - // Update the StoreCache - m_store_cache.remove(peek().m_subblock); - - // Dequeue the entry from the store buffer - dequeue(); - - if (isEmpty()) { - assert(m_store_cache.isEmpty()); - } - - if(type == CacheRequestType_ATOMIC) { - assert(isEmpty()); - } - - // See if we can remove any more entries - processHeadOfQueue(); -} - -void StoreBuffer::processHeadOfQueue() -{ - if(!isEmpty() && !m_pending) { - StoreBufferEntry& entry = peek(); - assert(m_pending == false); - m_pending = true; - m_pending_address = entry.m_subblock.getAddress(); - CacheMsg request(entry.m_subblock.getAddress(), entry.m_subblock.getAddress(), entry.m_type, entry.m_pc, entry.m_access_mode, entry.m_size, PrefetchBit_No, 0, Address(0), entry.m_thread); - m_chip_ptr->getSequencer(m_version)->doRequest(request); - } -} - -bool StoreBuffer::isReady() const -{ - return ((m_size < MAX_ENTRIES) && (!m_seen_atomic)); -} - -// Queue implementation methods - -StoreBufferEntry& StoreBuffer::peek() -{ - return getEntry(m_head); -} - -void StoreBuffer::dequeue() -{ - assert(m_size > 0); - m_size--; - inc_index(m_head); -} - -void StoreBuffer::enqueue(const StoreBufferEntry& entry) -{ - // assert(isReady()); - (*m_queue_ptr)[m_tail] = entry; - m_size++; - g_system_ptr->getProfiler()->storeBuffer(m_size, m_store_cache.size()); - inc_index(m_tail); -} - -StoreBufferEntry& StoreBuffer::getEntry(int index) -{ - return (*m_queue_ptr)[index]; -} - -void StoreBuffer::print(ostream& out) const -{ - out << "[StoreBuffer]"; -} - diff --git a/src/mem/ruby/system/StoreBuffer.hh b/src/mem/ruby/system/StoreBuffer.hh deleted file mode 100644 index 2c9283f4b..000000000 --- a/src/mem/ruby/system/StoreBuffer.hh +++ /dev/null @@ -1,121 +0,0 @@ - -/* - * 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. - */ - -/* - * $Id$ - * - * Description: - * - */ - -#ifndef StoreBuffer_H -#define StoreBuffer_H - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/common/Consumer.hh" -#include "mem/ruby/common/Address.hh" -#include "mem/protocol/AccessModeType.hh" -#include "mem/protocol/CacheRequestType.hh" -#include "mem/ruby/system/StoreCache.hh" - -class CacheMsg; -class DataBlock; -class SubBlock; -class StoreBufferEntry; -class AbstractChip; -class Packet; - -template <class TYPE> class Vector; - -class StoreBuffer : public Consumer { -public: - // Constructors - StoreBuffer(AbstractChip* chip_ptr, int version); - - // Destructor - ~StoreBuffer(); - - // Public Methods - void wakeup(); // Used only for deadlock detection - void callBack(const Address& addr, DataBlock& data, Packet* pkt); - void insertStore(Packet* pkt, const CacheMsg& request); - void updateSubBlock(SubBlock& sub_block) const { m_store_cache.update(sub_block); } - bool trySubBlock(const SubBlock& sub_block) const { assert(isReady()); return m_store_cache.check(sub_block); } - void print(ostream& out) const; - bool isEmpty() const { return (m_size == 0); } - bool isReady() const; - - // Class methods - static void printConfig(ostream& out); - -private: - // Private Methods - void processHeadOfQueue(); - - StoreBufferEntry& peek(); - void dequeue(); - void enqueue(const StoreBufferEntry& entry); - StoreBufferEntry& getEntry(int index); - - // Private copy constructor and assignment operator - StoreBuffer(const StoreBuffer& obj); - StoreBuffer& operator=(const StoreBuffer& obj); - - // Data Members (m_ prefix) - int m_version; - - Vector<StoreBufferEntry>* m_queue_ptr; - int m_head; - int m_tail; - int m_size; - - StoreCache m_store_cache; - - AbstractChip* m_chip_ptr; - bool m_pending; - Address m_pending_address; - bool m_seen_atomic; - bool m_deadlock_check_scheduled; -}; - -// Output operator declaration -ostream& operator<<(ostream& out, const StoreBuffer& obj); - -// ******************* Definitions ******************* - -// Output operator definition -extern inline -ostream& operator<<(ostream& out, const StoreBuffer& obj) -{ - obj.print(out); - out << flush; - return out; -} - -#endif //StoreBuffer_H diff --git a/src/mem/ruby/system/StoreCache.cc b/src/mem/ruby/system/StoreCache.cc deleted file mode 100644 index a11b2ac50..000000000 --- a/src/mem/ruby/system/StoreCache.cc +++ /dev/null @@ -1,178 +0,0 @@ - -/* - * 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. - */ - -/* - * $Id$ - * - */ - -#include "mem/ruby/system/StoreCache.hh" -#include "mem/ruby/system/System.hh" -#include "mem/ruby/common/Driver.hh" -#include "mem/gems_common/Vector.hh" -#include "mem/ruby/common/DataBlock.hh" -#include "mem/ruby/common/SubBlock.hh" -#include "mem/gems_common/Map.hh" - -// Helper class -struct StoreCacheEntry { - StoreCacheEntry() { - m_byte_counters.setSize(RubyConfig::dataBlockBytes()); - for(int i=0; i<m_byte_counters.size(); i++) { - m_byte_counters[i] = 0; - } - m_line_counter = 0; - - } - Address m_addr; - DataBlock m_datablock; - Vector<int> m_byte_counters; - int m_line_counter; -}; - -StoreCache::StoreCache() -{ - m_internal_cache_ptr = new Map<Address, StoreCacheEntry>; -} - -StoreCache::~StoreCache() -{ - delete m_internal_cache_ptr; -} - -bool StoreCache::isEmpty() const -{ - return m_internal_cache_ptr->size() == 0; -} - -int StoreCache::size() const { return m_internal_cache_ptr->size(); } - -void StoreCache::add(const SubBlock& block) -{ - if (m_internal_cache_ptr->exist(line_address(block.getAddress())) == false) { - m_internal_cache_ptr->allocate(line_address(block.getAddress())); - } - - StoreCacheEntry& entry = m_internal_cache_ptr->lookup(line_address(block.getAddress())); - - // For each byte in entry change the bytes and inc. the counters - int starting_offset = block.getAddress().getOffset(); - int size = block.getSize(); - for (int index=0; index < size; index++) { - // Update counter - entry.m_byte_counters[starting_offset+index]++; - - // Record data - entry.m_datablock.setByte(starting_offset+index, block.getByte(index)); - - DEBUG_EXPR(SEQUENCER_COMP, LowPrio, block.getAddress()); - DEBUG_EXPR(SEQUENCER_COMP, LowPrio, int(block.getByte(index))); - DEBUG_EXPR(SEQUENCER_COMP, LowPrio, starting_offset+index); - } - - // Increment the counter - entry.m_line_counter++; -} - -void StoreCache::remove(const SubBlock& block) -{ - assert(m_internal_cache_ptr->exist(line_address(block.getAddress()))); - - StoreCacheEntry& entry = m_internal_cache_ptr->lookup(line_address(block.getAddress())); - - // Decrement the byte counters - int starting_offset = block.getAddress().getOffset(); - int size = block.getSize(); - for (int index=0; index < size; index++) { - // Update counter - entry.m_byte_counters[starting_offset+index]--; - } - - // Decrement the line counter - entry.m_line_counter--; - assert(entry.m_line_counter >= 0); - - // Check to see if we should de-allocate this entry - if (entry.m_line_counter == 0) { - m_internal_cache_ptr->deallocate(line_address(block.getAddress())); - } -} - -bool StoreCache::check(const SubBlock& block) const -{ - if (m_internal_cache_ptr->exist(line_address(block.getAddress())) == false) { - return false; - } else { - // Lookup the entry - StoreCacheEntry& entry = m_internal_cache_ptr->lookup(line_address(block.getAddress())); - - // See if all the bytes are valid - int starting_offset = block.getAddress().getOffset(); - int size = block.getSize(); - for (int index=0; index < size; index++) { - if (entry.m_byte_counters[starting_offset+index] > 0) { - // So far so good - } else { - // not all the bytes were valid - return false; - } - } - } - return true; -} - -void StoreCache::update(SubBlock& block) const -{ - if (m_internal_cache_ptr->exist(line_address(block.getAddress()))) { - // Lookup the entry - StoreCacheEntry& entry = m_internal_cache_ptr->lookup(line_address(block.getAddress())); - - // Copy all appropriate and valid bytes from the store cache to - // the SubBlock - int starting_offset = block.getAddress().getOffset(); - int size = block.getSize(); - for (int index=0; index < size; index++) { - - DEBUG_EXPR(SEQUENCER_COMP, LowPrio, block.getAddress()); - DEBUG_EXPR(SEQUENCER_COMP, LowPrio, int(entry.m_datablock.getByte(starting_offset+index))); - DEBUG_EXPR(SEQUENCER_COMP, LowPrio, starting_offset+index); - - // If this byte is valid, copy the data into the sub-block - if (entry.m_byte_counters[starting_offset+index] > 0) { - block.setByte(index, entry.m_datablock.getByte(starting_offset+index)); - } - } - } -} - -void StoreCache::print(ostream& out) const -{ - out << "[StoreCache]"; -} - diff --git a/src/mem/ruby/system/StoreCache.hh b/src/mem/ruby/system/StoreCache.hh deleted file mode 100644 index 81eecde38..000000000 --- a/src/mem/ruby/system/StoreCache.hh +++ /dev/null @@ -1,85 +0,0 @@ - -/* - * 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. - */ - -/* - * $Id$ - * - * Description: - * - */ - -#ifndef StoreCache_H -#define StoreCache_H - -#include "mem/ruby/common/Global.hh" -#include "mem/ruby/common/Address.hh" - - -class DataBlock; -class SubBlock; -class StoreCacheEntry; - -template <class KEY_TYPE, class VALUE_TYPE> class Map; - -class StoreCache { -public: - // Constructors - StoreCache(); - - // Destructor - ~StoreCache(); - - // Public Methods - void add(const SubBlock& block); - void remove(const SubBlock& block); - bool check(const SubBlock& block) const; - void update(SubBlock& block) const; - bool isEmpty() const; - int size() const; - void print(ostream& out) const; - -private: - Map<Address, StoreCacheEntry>* m_internal_cache_ptr; -}; - -// Output operator declaration -ostream& operator<<(ostream& out, const StoreCache& obj); - -// ******************* Definitions ******************* - -// Output operator definition -extern inline -ostream& operator<<(ostream& out, const StoreCache& obj) -{ - obj.print(out); - out << flush; - return out; -} - -#endif //StoreCache_H diff --git a/src/mem/ruby/system/System.cc b/src/mem/ruby/system/System.cc index 0e1a29130..9d1119f01 100644 --- a/src/mem/ruby/system/System.cc +++ b/src/mem/ruby/system/System.cc @@ -38,134 +38,306 @@ #include "mem/ruby/system/System.hh" +#include "mem/ruby/common/Address.hh" #include "mem/ruby/profiler/Profiler.hh" #include "mem/ruby/network/Network.hh" -#include "mem/ruby/tester/Tester.hh" -#include "mem/ruby/tester/SyntheticDriver.hh" -#include "mem/ruby/tester/DeterministicDriver.hh" -#include "mem/protocol/Chip.hh" -//#include "mem/ruby/recorder/Tracer.hh" +#include "mem/ruby/recorder/Tracer.hh" #include "mem/protocol/Protocol.hh" - -RubySystem::RubySystem() +#include "mem/ruby/buffers/MessageBuffer.hh" +#include "mem/ruby/system/Sequencer.hh" +#include "mem/ruby/system/DMASequencer.hh" +#include "mem/ruby/system/MemoryVector.hh" +#include "mem/protocol/ControllerFactory.hh" +#include "mem/ruby/slicc_interface/AbstractController.hh" +#include "mem/ruby/system/CacheMemory.hh" +#include "mem/ruby/system/DirectoryMemory.hh" +#include "mem/ruby/network/simple/Topology.hh" +#include "mem/ruby/network/simple/SimpleNetwork.hh" +#include "mem/ruby/system/RubyPort.hh" +#include "mem/ruby/network/garnet-flexible-pipeline/GarnetNetwork.hh" +#include "mem/ruby/network/garnet-fixed-pipeline/GarnetNetwork_d.hh" +#include "mem/ruby/system/MemoryControl.hh" + +int RubySystem::m_random_seed; +bool RubySystem::m_randomization; +int RubySystem::m_tech_nm; +int RubySystem::m_freq_mhz; +int RubySystem::m_block_size_bytes; +int RubySystem::m_block_size_bits; +uint64 RubySystem::m_memory_size_bytes; +int RubySystem::m_memory_size_bits; + +map< string, RubyPort* > RubySystem::m_ports; +map< string, CacheMemory* > RubySystem::m_caches; +map< string, DirectoryMemory* > RubySystem::m_directories; +map< string, Sequencer* > RubySystem::m_sequencers; +map< string, DMASequencer* > RubySystem::m_dma_sequencers; +map< string, AbstractController* > RubySystem::m_controllers; +map< string, MemoryControl* > RubySystem::m_memorycontrols; + + +Network* RubySystem::m_network_ptr; +map< string, Topology*> RubySystem::m_topologies; +Profiler* RubySystem::m_profiler_ptr; +Tracer* RubySystem::m_tracer_ptr; + +MemoryVector* RubySystem::m_mem_vec_ptr; + + +RubySystem* RubySystem::create(const vector <RubyObjConf> & sys_conf) { - init(); - m_preinitialized_driver = false; - createDriver(); - - /* gem5:Binkert for decomissiong of tracer - m_tracer_ptr = new Tracer; - */ - - /* gem5:Arka for decomissiong of log_tm - if (XACT_MEMORY) { - m_xact_isolation_checker = new XactIsolationChecker; - m_xact_commit_arbiter = new XactCommitArbiter; - m_xact_visualizer = new XactVisualizer; - } -*/ + if (g_system_ptr == NULL) + return new RubySystem(sys_conf); + return g_system_ptr; } -RubySystem::RubySystem(Driver* _driver) +void RubySystem::init(const vector<string> & argv) { - init(); - m_preinitialized_driver = true; - m_driver_ptr = _driver; -} + for (size_t i=0; i < argv.size(); i+=2) { + if (argv[i] == "random_seed") { + m_random_seed = atoi(argv[i+1].c_str()); + srandom(m_random_seed); + } else if (argv[i] == "randomization") { + m_randomization = string_to_bool(argv[i+1]); + } else if (argv[i] == "tech_nm") { + m_tech_nm = atoi(argv[i+1].c_str()); + } else if (argv[i] == "freq_mhz") { + m_freq_mhz = atoi(argv[i+1].c_str()); + } else if (argv[i] == "block_size_bytes") { + m_block_size_bytes = atoi(argv[i+1].c_str()); + assert(is_power_of_2(m_block_size_bytes)); + m_block_size_bits = log_int(m_block_size_bytes); + } else if (argv[i] == "debug") { + + } else if (argv[i] == "tracer") { + + } else if (argv[i] == "profiler") { + + // } else if (argv[i] == "MI_example") { -RubySystem::~RubySystem() -{ - for (int i = 0; i < m_chip_vector.size(); i++) { - delete m_chip_vector[i]; + } else { + cerr << "Error: Unknown RubySystem config parameter -- " << argv[i] << endl; + assert(0); + } } - if (!m_preinitialized_driver) - delete m_driver_ptr; - delete m_network_ptr; - delete m_profiler_ptr; - /* gem5:Binkert for decomissiong of tracer - delete m_tracer_ptr; - */ } -void RubySystem::init() +RubySystem::RubySystem(const vector <RubyObjConf> & sys_conf) { - DEBUG_MSG(SYSTEM_COMP, MedPrio,"initializing"); - - m_driver_ptr = NULL; - m_profiler_ptr = new Profiler; + // DEBUG_MSG(SYSTEM_COMP, MedPrio,"initializing"); + + for (size_t i=0;i<sys_conf.size(); i++) { + const string & type = sys_conf[i].type; + const string & name = sys_conf[i].name; + const vector<string> & argv = sys_conf[i].argv; + if (type == "RubySystem") { + init(argv); // initialize system-wide variables before doing anything else! + } else if (type == "Debug") { + g_debug_ptr = new Debug(name, argv); + } + } - // NETWORK INITIALIZATION - // create the network by calling a function that calls new - m_network_ptr = Network::createNetwork(RubyConfig::numberOfChips()); + assert( g_debug_ptr != NULL); + g_eventQueue_ptr = new RubyEventQueue; + g_system_ptr = this; + m_mem_vec_ptr = new MemoryVector; + + /* object contruction is broken into two steps (Constructor and init) to avoid cyclic dependencies + * e.g. a sequencer needs a pointer to a controller and a controller needs a pointer to a sequencer + */ + + vector<string> memory_control_names; + + for (size_t i=0;i<sys_conf.size(); i++) { + const string & type = sys_conf[i].type; + const string & name = sys_conf[i].name; + const vector<string> & argv = sys_conf[i].argv; + if (type == "RubySystem" || type == "Debug") + continue; + else if (type == "SetAssociativeCache") + m_caches[name] = new CacheMemory(name); + else if (type == "DirectoryMemory") + m_directories[name] = new DirectoryMemory(name); + else if (type == "Sequencer") { + m_sequencers[name] = new Sequencer(name); + m_ports[name] = m_sequencers[name]; + } else if (type == "DMASequencer") { + m_dma_sequencers[name] = new DMASequencer(name); + m_ports[name] = m_dma_sequencers[name]; + } else if (type == "Topology") { + assert(m_topologies.size() == 0); // only one toplogy at a time is supported right now + m_topologies[name] = new Topology(name); + } else if (type == "SimpleNetwork") { + assert(m_network_ptr == NULL); // only one network at a time is supported right now + m_network_ptr = new SimpleNetwork(name); + } else if (type.find("generated") == 0) { + string controller_type = type.substr(10); + m_controllers[name] = ControllerFactory::createController(controller_type, name); +// printf ("ss: generated %s \n", controller_type); +//added by SS + } else if (type == "Tracer") { + //m_tracers[name] = new Tracer(name); + m_tracer_ptr = new Tracer(name); + } else if (type == "Profiler") { + m_profiler_ptr = new Profiler(name); + } else if (type == "GarnetNetwork") { + assert(m_network_ptr == NULL); // only one network at a time is supported right now + m_network_ptr = new GarnetNetwork(name); + } else if (type == "GarnetNetwork_d") { + assert(m_network_ptr == NULL); // only one network at a time is supported right now + m_network_ptr = new GarnetNetwork_d(name); + } else if (type == "MemoryControl") { + m_memorycontrols[name] = new MemoryControl(name); + memory_control_names.push_back (name); + } else { + cerr << "Error: Unknown object type -- " << type << endl; + assert(0); + } + } - DEBUG_MSG(SYSTEM_COMP, MedPrio,"Constructed network"); + for (size_t i=0;i<sys_conf.size(); i++) { + string type = sys_conf[i].type; + string name = sys_conf[i].name; + const vector<string> & argv = sys_conf[i].argv; + if (type == "Topology") + m_topologies[name]->init(argv); + } - // CHIP INITIALIZATION - m_chip_vector.setSize(RubyConfig::numberOfChips());// create the vector of pointers to processors - for(int i=0; i<RubyConfig::numberOfChips(); i++) { // for each chip - // create the chip - m_chip_vector[i] = new Chip(i, m_network_ptr); - DEBUG_MSG(SYSTEM_COMP, MedPrio,"Constructed a chip"); + for (size_t i=0;i<sys_conf.size(); i++) { + string type = sys_conf[i].type; + string name = sys_conf[i].name; + const vector<string> & argv = sys_conf[i].argv; + if (type == "SimpleNetwork" || type == "GarnetNetwork" || type == "GarnetNetwork_d"){ + m_network_ptr->init(argv); + } } - // These must be after the chips are constructed + for (size_t i=0;i<sys_conf.size(); i++) { + string type = sys_conf[i].type; + string name = sys_conf[i].name; + const vector<string> & argv = sys_conf[i].argv; + if (type == "MemoryControl" ){ + m_memorycontrols[name]->init(argv); + } + } -#if 0 - if (!g_SIMICS) { - if (g_SYNTHETIC_DRIVER && !g_DETERMINISTIC_DRIVER) { - m_driver_ptr = new SyntheticDriver(this); - } else if (!g_SYNTHETIC_DRIVER && g_DETERMINISTIC_DRIVER) { - m_driver_ptr = new DeterministicDriver(this); - } else if (g_SYNTHETIC_DRIVER && g_DETERMINISTIC_DRIVER) { - ERROR_MSG("SYNTHETIC and DETERMINISTIC DRIVERS are exclusive and cannot be both enabled"); - } else { - // normally make tester object, otherwise make an opal interface object. - if (!OpalInterface::isOpalLoaded()) { - m_driver_ptr = new Tester(this); - } else { - m_driver_ptr = new OpalInterface(this); - } + for (size_t i=0;i<sys_conf.size(); i++) { + string type = sys_conf[i].type; + string name = sys_conf[i].name; + const vector<string> & argv = sys_conf[i].argv; + if (type == "RubySystem" || type == "Debug") + continue; + else if (type == "SetAssociativeCache") + m_caches[name]->init(argv); + else if (type == "DirectoryMemory") + m_directories[name]->init(argv); + else if (type == "MemoryControl") + continue; + else if (type == "Sequencer") + m_sequencers[name]->init(argv); + else if (type == "DMASequencer") + m_dma_sequencers[name]->init(argv); + else if (type == "Topology") + continue; + else if (type == "SimpleNetwork" || type == "GarnetNetwork" || type == "GarnetNetwork_d") + continue; + else if (type.find("generated") == 0) { + string controller_type = type.substr(11); + m_controllers[name]->init(m_network_ptr, argv); } - } else { - // detect if opal is loaded or not - if (OpalInterface::isOpalLoaded()) { - m_driver_ptr = new OpalInterface(this); - } else { +//added by SS + else if (type == "Tracer") + //m_tracers[name]->init(argv); + m_tracer_ptr->init(argv); + else if (type == "Profiler") + m_profiler_ptr->init(argv, memory_control_names); +// else if (type == "MI_example"){ +// } + else assert(0); - /* Need to allocate a driver here */ - // m_driver_ptr = new SimicsDriver(this); - } } -#endif + +// m_profiler_ptr = new Profiler; + + // calculate system-wide parameters + m_memory_size_bytes = 0; + DirectoryMemory* prev = NULL; + for (map< string, DirectoryMemory*>::const_iterator it = m_directories.begin(); + it != m_directories.end(); it++) { + if (prev != NULL) + assert((*it).second->getSize() == prev->getSize()); // must be equal for proper address mapping + m_memory_size_bytes += (*it).second->getSize(); + prev = (*it).second; + } + m_mem_vec_ptr->setSize(m_memory_size_bytes); + m_memory_size_bits = log_int(m_memory_size_bytes); + +// m_tracer_ptr = new Tracer; DEBUG_MSG(SYSTEM_COMP, MedPrio,"finished initializing"); DEBUG_NEWLINE(SYSTEM_COMP, MedPrio); } -void RubySystem::createDriver() +RubySystem::~RubySystem() { - if (g_SYNTHETIC_DRIVER && !g_DETERMINISTIC_DRIVER) { - cerr << "Creating Synthetic Driver" << endl; - m_driver_ptr = new SyntheticDriver(this); - } else if (!g_SYNTHETIC_DRIVER && g_DETERMINISTIC_DRIVER) { - cerr << "Creating Deterministic Driver" << endl; - m_driver_ptr = new DeterministicDriver(this); + /* + for (int i=0; i < MachineType_base_level(MachineType_NUM); i++) { + for (int j=0; j < RubyConfig::getNumberOfControllersPerType(i); j++ ) { + delete m_controllers[i][j]; } + } + delete m_network_ptr; + delete m_profiler_ptr; + delete m_tracer_ptr; + */ +} + +void RubySystem::printSystemConfig(ostream & out) +{ + out << "RubySystem config:" << endl; + out << " random_seed: " << m_random_seed << endl; + out << " randomization: " << m_randomization << endl; + out << " tech_nm: " << m_tech_nm << endl; + out << " freq_mhz: " << m_freq_mhz << endl; + out << " block_size_bytes: " << m_block_size_bytes << endl; + out << " block_size_bits: " << m_block_size_bits << endl; + out << " memory_size_bytes: " << m_memory_size_bytes << endl; + out << " memory_size_bits: " << m_memory_size_bits << endl; + } -void RubySystem::printConfig(ostream& out) const +void RubySystem::printConfig(ostream& out) { out << "\n================ Begin RubySystem Configuration Print ================\n\n"; - RubyConfig::printConfiguration(out); - out << endl; - getChip(0)->printConfig(out); + // RubyConfig::printConfiguration(out); + // out << endl; + printSystemConfig(out); + for (map<string, AbstractController*>::const_iterator it = m_controllers.begin(); + it != m_controllers.end(); it++) { + (*it).second->printConfig(out); + } + for (map<string, CacheMemory*>::const_iterator it = m_caches.begin(); + it != m_caches.end(); it++) { + (*it).second->printConfig(out); + } + DirectoryMemory::printGlobalConfig(out); + for (map<string, DirectoryMemory*>::const_iterator it = m_directories.begin(); + it != m_directories.end(); it++) { + (*it).second->printConfig(out); + } + for (map<string, Sequencer*>::const_iterator it = m_sequencers.begin(); + it != m_sequencers.end(); it++) { + (*it).second->printConfig(out); + } + m_network_ptr->printConfig(out); - m_driver_ptr->printConfig(out); m_profiler_ptr->printConfig(out); + out << "\n================ End RubySystem Configuration Print ================\n\n"; } void RubySystem::printStats(ostream& out) { + const time_t T = time(NULL); tm *localTime = localtime(&T); char buf[100]; @@ -174,32 +346,30 @@ void RubySystem::printStats(ostream& out) out << "Real time: " << buf << endl; m_profiler_ptr->printStats(out); - for(int i=0; i<RubyConfig::numberOfChips(); i++) { // for each chip - for(int p=0; p<RubyConfig::numberOfProcsPerChip(); p++) { - m_chip_vector[i]->m_L1Cache_mandatoryQueue_vec[p]->printStats(out); - } - } m_network_ptr->printStats(out); - m_driver_ptr->printStats(out); - Chip::printStats(out); + for (map<string, AbstractController*>::const_iterator it = m_controllers.begin(); + it != m_controllers.end(); it++) { + (*it).second->printStats(out); + } } void RubySystem::clearStats() const { + /* m_profiler_ptr->clearStats(); + for (int i=0; i<m_rubyRequestQueues.size(); i++) + for (int j=0;j<m_rubyRequestQueues[i].size(); j++) + m_rubyRequestQueues[i][j]->clearStats(); m_network_ptr->clearStats(); - m_driver_ptr->clearStats(); - Chip::clearStats(); - for(int i=0; i<RubyConfig::numberOfChips(); i++) { // for each chip - for(int p=0; p<RubyConfig::numberOfProcsPerChip(); p++) { - m_chip_vector[i]->m_L1Cache_mandatoryQueue_vec[p]->clearStats(); - } - } + for (int i=0; i < MachineType_base_level(MachineType_NUM); i++) + m_controllers[i][0]->clearStats(); + */ } void RubySystem::recordCacheContents(CacheRecorder& tr) const { - for (int i = 0; i < m_chip_vector.size(); i++) { + /* + for (int i = 0; i < m_chip_vector.size(); i++) { for (int m_version = 0; m_version < RubyConfig::numberOfProcsPerChip(); m_version++) { if (Protocol::m_TwoLevelCache) { m_chip_vector[i]->m_L1Cache_L1IcacheMemory_vec[m_version]->setAsInstructionCache(true); @@ -210,6 +380,7 @@ void RubySystem::recordCacheContents(CacheRecorder& tr) const } m_chip_vector[i]->recordCacheContents(tr); } + */ } #ifdef CHECK_COHERENCE @@ -222,7 +393,7 @@ void RubySystem::recordCacheContents(CacheRecorder& tr) const // and "isBlockExclusive" that are specific to that protocol // void RubySystem::checkGlobalCoherenceInvariant(const Address& addr ) { - + /* NodeID exclusive = -1; bool sharedDetected = false; NodeID lastShared = -1; @@ -262,6 +433,7 @@ void RubySystem::checkGlobalCoherenceInvariant(const Address& addr ) { } } } + */ } #endif diff --git a/src/mem/ruby/system/System.hh b/src/mem/ruby/system/System.hh index bc493dd16..40c425ad7 100644 --- a/src/mem/ruby/system/System.hh +++ b/src/mem/ruby/system/System.hh @@ -41,81 +41,129 @@ #ifndef SYSTEM_H #define SYSTEM_H +#include "mem/ruby/system/RubyPort.hh" #include "mem/ruby/common/Global.hh" #include "mem/gems_common/Vector.hh" -#include "mem/ruby/common/Address.hh" -#include "mem/ruby/config/RubyConfig.hh" -#include "mem/protocol/MachineType.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" +#include "mem/ruby/eventqueue/RubyEventQueue.hh" +#include <map> class Profiler; class Network; -class Driver; class CacheRecorder; class Tracer; class Sequencer; -class XactIsolationChecker; -class XactCommitArbiter; -class XactVisualizer; -class TransactionInterfaceManager; +class DMASequencer; +class MemoryVector; +class AbstractController; +class MessageBuffer; +class CacheMemory; +class DirectoryMemory; +class Topology; +class MemoryControl; + +struct RubyObjConf { + string type; + string name; + vector<string> argv; + RubyObjConf(string _type, string _name, vector<string> _argv) + : type(_type), name(_name), argv(_argv) + {} +}; class RubySystem { public: - // Constructors - RubySystem(); - RubySystem(Driver* _driver); // used when driver is already instantiated (e.g. M5's RubyMem) - + static RubySystem* create(const vector <RubyObjConf> & sys_conf); // Destructor ~RubySystem(); + // config accessors + static int getRandomSeed() { return m_random_seed; } + static int getRandomization() { return m_randomization; } + static int getTechNm() { return m_tech_nm; } + static int getFreqMhz() { return m_freq_mhz; } + static int getBlockSizeBytes() { return m_block_size_bytes; } + static int getBlockSizeBits() { return m_block_size_bits; } + static uint64 getMemorySizeBytes() { return m_memory_size_bytes; } + static int getMemorySizeBits() { return m_memory_size_bits; } + // Public Methods - int getNumProcessors() { return RubyConfig::numberOfProcessors(); } - int getNumMemories() { return RubyConfig::numberOfMemories(); } - Profiler* getProfiler() { return m_profiler_ptr; } - Driver* getDriver() { assert(m_driver_ptr != NULL); return m_driver_ptr; } + static RubyPort* getPortOnly(const string & name) { + assert(m_ports.count(name) == 1); return m_ports[name]; } + static RubyPort* getPort(const string & name, void (*hit_callback)(int64_t)) { + 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]; } + static DirectoryMemory* getDirectory(const string & name) { assert(m_directories.count(name) == 1); return m_directories[name]; } + static MemoryControl* getMemoryControl(const string & name) { assert(m_memorycontrols.count(name) == 1); return m_memorycontrols[name]; } + static Sequencer* getSequencer(const string & name) { assert(m_sequencers.count(name) == 1); return m_sequencers[name]; } + static DMASequencer* getDMASequencer(const string & name) { assert(m_dma_sequencers.count(name) == 1); return m_dma_sequencers[name]; } + static AbstractController* getController(const string & name) { assert(m_controllers.count(name) == 1); return m_controllers[name]; } + + static RubyEventQueue* getEventQueue() { return g_eventQueue_ptr; } + + static int getNumberOfDirectories() { return m_directories.size(); } + static int getNumberOfSequencers() { return m_sequencers.size(); } + + Profiler* getProfiler() {assert(m_profiler_ptr != NULL); return m_profiler_ptr; } Tracer* getTracer() { assert(m_tracer_ptr != NULL); return m_tracer_ptr; } - Network* getNetwork() { assert(m_network_ptr != NULL); return m_network_ptr; } - XactIsolationChecker* getXactIsolationChecker() { assert(m_xact_isolation_checker!= NULL); return m_xact_isolation_checker;} - XactCommitArbiter* getXactCommitArbiter() { assert(m_xact_commit_arbiter!= NULL); return m_xact_commit_arbiter;} - XactVisualizer* getXactVisualizer() { assert(m_xact_visualizer!= NULL); return m_xact_visualizer;} - - AbstractChip* getChip(int chipNumber) const { assert(m_chip_vector[chipNumber] != NULL); return m_chip_vector[chipNumber];} - Sequencer* getSequencer(int procNumber) const { - assert(procNumber < RubyConfig::numberOfProcessors()); - return m_chip_vector[procNumber/RubyConfig::numberOfProcsPerChip()]->getSequencer(procNumber%RubyConfig::numberOfProcsPerChip()); - } - TransactionInterfaceManager* getTransactionInterfaceManager(int procNumber) const { - return m_chip_vector[procNumber/RubyConfig::numberOfProcsPerChip()]->getTransactionInterfaceManager(procNumber%RubyConfig::numberOfProcsPerChip()); - } + static MemoryVector* getMemoryVector() { assert(m_mem_vec_ptr != NULL); return m_mem_vec_ptr;} + void recordCacheContents(CacheRecorder& tr) const; - void printConfig(ostream& out) const; - void printStats(ostream& out); + static void printConfig(ostream& out); + static void printStats(ostream& out); void clearStats() const; + uint64 getInstructionCount(int thread) { return 1; } + static uint64 getCycleCount(int thread) { return g_eventQueue_ptr->getTime(); } + void print(ostream& out) const; + /* #ifdef CHECK_COHERENCE void checkGlobalCoherenceInvariant(const Address& addr); #endif + */ private: - // Private Methods - void init(); - void createDriver(); + // Constructors + RubySystem(const vector <RubyObjConf> & cfg_file); // Private copy constructor and assignment operator RubySystem(const RubySystem& obj); RubySystem& operator=(const RubySystem& obj); + void init(const vector<string> & argv); + + static void printSystemConfig(ostream& out); + +private: + // configuration parameters + static int m_random_seed; + static bool m_randomization; + static int m_tech_nm; + static int m_freq_mhz; + static int m_block_size_bytes; + static int m_block_size_bits; + static uint64 m_memory_size_bytes; + static int m_memory_size_bits; + // Data Members (m_ prefix) - Network* m_network_ptr; - Vector<AbstractChip*> m_chip_vector; - Profiler* m_profiler_ptr; - bool m_preinitialized_driver; - Driver* m_driver_ptr; - Tracer* m_tracer_ptr; - XactIsolationChecker *m_xact_isolation_checker; - XactCommitArbiter *m_xact_commit_arbiter; - XactVisualizer *m_xact_visualizer; + static Network* m_network_ptr; + static map< string, Topology* > m_topologies; + static map< string, RubyPort* > m_ports; + static map< string, CacheMemory* > m_caches; + static map< string, DirectoryMemory* > m_directories; + static map< string, Sequencer* > m_sequencers; + static map< string, DMASequencer* > m_dma_sequencers; + static map< string, AbstractController* > m_controllers; + static map< string, MemoryControl* > m_memorycontrols; + + //added by SS + //static map< string, Tracer* > m_tracers; + + static Profiler* m_profiler_ptr; + static Tracer* m_tracer_ptr; + static MemoryVector* m_mem_vec_ptr; }; // Output operator declaration diff --git a/src/mem/ruby/system/TBETable.hh b/src/mem/ruby/system/TBETable.hh index 2a0c78f06..7d2daa55a 100644 --- a/src/mem/ruby/system/TBETable.hh +++ b/src/mem/ruby/system/TBETable.hh @@ -43,7 +43,6 @@ #include "mem/gems_common/Map.hh" #include "mem/ruby/common/Address.hh" #include "mem/ruby/profiler/Profiler.hh" -#include "mem/ruby/slicc_interface/AbstractChip.hh" #include "mem/ruby/system/System.hh" template<class ENTRY> @@ -51,19 +50,20 @@ class TBETable { public: // Constructors - TBETable(AbstractChip* chip_ptr); + TBETable(int number_of_TBEs); + // Destructor //~TBETable(); // Public Methods - static void printConfig(ostream& out) { out << "TBEs_per_TBETable: " << NUMBER_OF_TBES << endl; } + void printConfig(ostream& out) { out << "TBEs_per_TBETable: " << m_number_of_TBEs << endl; } bool isPresent(const Address& address) const; void allocate(const Address& address); void deallocate(const Address& address); - bool areNSlotsAvailable(int n) const { return (NUMBER_OF_TBES - m_map.size()) >= n; } + bool areNSlotsAvailable(int n) const { return (m_number_of_TBEs - m_map.size()) >= n; } ENTRY& lookup(const Address& address); const ENTRY& lookup(const Address& address) const; @@ -79,7 +79,9 @@ private: // Data Members (m_prefix) Map<Address, ENTRY> m_map; - AbstractChip* m_chip_ptr; + +private: + int m_number_of_TBEs; }; // Output operator declaration @@ -100,11 +102,12 @@ ostream& operator<<(ostream& out, const TBETable<ENTRY>& obj) // **************************************************************** + template<class ENTRY> extern inline -TBETable<ENTRY>::TBETable(AbstractChip* chip_ptr) +TBETable<ENTRY>::TBETable(int number_of_TBEs) { - m_chip_ptr = chip_ptr; + m_number_of_TBEs = number_of_TBEs; } // PUBLIC METHODS @@ -115,7 +118,7 @@ extern inline bool TBETable<ENTRY>::isPresent(const Address& address) const { assert(address == line_address(address)); - assert(m_map.size() <= NUMBER_OF_TBES); + assert(m_map.size() <= m_number_of_TBEs); return m_map.exist(address); } @@ -124,7 +127,7 @@ extern inline void TBETable<ENTRY>::allocate(const Address& address) { assert(isPresent(address) == false); - assert(m_map.size() < NUMBER_OF_TBES); + assert(m_map.size() < m_number_of_TBEs); g_system_ptr->getProfiler()->L2tbeUsageSample(m_map.size()); m_map.add(address, ENTRY()); } |