From: Derek Hower Date: Tue, 19 Jan 2010 21:48:12 +0000 (-0600) Subject: merge X-Git-Tag: stable_2012_02_02~1575^2~1^2~2 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=279f179babc9e5663156777c533c06edc91bce9a;p=gem5.git merge --- 279f179babc9e5663156777c533c06edc91bce9a diff --cc src/mem/protocol/RubySlicc_ComponentMapping.sm index 0da1a05e2,2a027554e..891820c46 --- a/src/mem/protocol/RubySlicc_ComponentMapping.sm +++ b/src/mem/protocol/RubySlicc_ComponentMapping.sm @@@ -29,9 -29,10 +29,11 @@@ // Mapping functions + int getNumberOfLastLevelCaches(); + // NodeID map_address_to_node(Address addr); MachineID mapAddressToRange(Address addr, MachineType type, int low, int high); +NetDest broadcast(MachineType type); MachineID map_Address_to_DMA(Address addr); MachineID map_Address_to_Directory(Address addr); NodeID map_Address_to_DirectoryNode(Address addr); diff --cc src/mem/protocol/SConsopts index ded0814d2,7be9fd97e..10a303681 --- a/src/mem/protocol/SConsopts +++ b/src/mem/protocol/SConsopts @@@ -47,9 -47,10 +47,10 @@@ all_protocols = 'MOSI_SMP_bcast_m', 'MOSI_SMP_directory_1level', 'MSI_MOSI_CMP_directory', + 'MOESI_hammer', ] --opt = EnumVariable('PROTOCOL', 'Coherence Protocol for Ruby', 'MI_example', ++opt = EnumVariable('PROTOCOL', 'Coherence Protocol for Ruby', 'MOESI_CMP_directory', all_protocols) sticky_vars.AddVariables(opt) diff --cc src/mem/ruby/config/TwoLevel_SplitL1UnifiedL2.rb index a4a1982f4,566055f74..a8ef1eceb --- a/src/mem/ruby/config/TwoLevel_SplitL1UnifiedL2.rb +++ b/src/mem/ruby/config/TwoLevel_SplitL1UnifiedL2.rb @@@ -26,8 -26,7 +26,8 @@@ num_memories = memory_size_mb = 1024 num_dma = 1 -protocol = "MOESI_CMP_token" +#default protocol - protocol = ""#"MESI_CMP_directory" ++protocol = "MOESI_CMP_directory" # check for overrides diff --cc src/mem/ruby/system/CacheMemory.cc index 000000000,630b94542..cf3e094ad mode 000000,100644..100644 --- a/src/mem/ruby/system/CacheMemory.cc +++ b/src/mem/ruby/system/CacheMemory.cc @@@ -1,0 -1,487 +1,483 @@@ + /* + * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + #include "mem/ruby/system/CacheMemory.hh" + + int CacheMemory::m_num_last_level_caches = 0; + MachineType CacheMemory::m_last_level_machine_type = MachineType_FIRST; + + // Output operator declaration + //ostream& operator<<(ostream& out, const CacheMemory& obj); + + // ******************* Definitions ******************* + + // Output operator definition + ostream& operator<<(ostream& out, const CacheMemory& obj) + { + obj.print(out); + out << flush; + return out; + } + + + // **************************************************************** + + CacheMemory::CacheMemory(const string & name) + : m_cache_name(name) + { + m_profiler_ptr = new CacheProfiler(name); + } + + void CacheMemory::init(const vector & argv) + { + int cache_size = -1; + string policy; + + m_num_last_level_caches = + MachineType_base_count(MachineType_FIRST); + m_controller = NULL; + for (uint32 i=0; igetMachineType()) { + m_num_last_level_caches = + MachineType_base_count(m_controller->getMachineType()); + m_last_level_machine_type = + m_controller->getMachineType(); + } + } else { + cerr << "WARNING: CacheMemory: Unknown configuration parameter: " << argv[i] << endl; + } + } + - assert(cache_size != -1); - - m_cache_num_sets = (cache_size / m_cache_assoc) / RubySystem::getBlockSizeBytes(); - assert(m_cache_num_sets > 1); ++ int num_lines = cache_size/RubySystem::getBlockSizeBytes(); ++ m_cache_num_sets = num_lines / m_cache_assoc; + m_cache_num_set_bits = log_int(m_cache_num_sets); + assert(m_cache_num_set_bits > 0); + + if(policy == "PSEUDO_LRU") + m_replacementPolicy_ptr = new PseudoLRUPolicy(m_cache_num_sets, m_cache_assoc); + else if (policy == "LRU") + m_replacementPolicy_ptr = new LRUPolicy(m_cache_num_sets, m_cache_assoc); + else + assert(false); + + m_cache.setSize(m_cache_num_sets); + m_locked.setSize(m_cache_num_sets); + for (int i = 0; i < m_cache_num_sets; i++) { + m_cache[i].setSize(m_cache_assoc); + m_locked[i].setSize(m_cache_assoc); + for (int j = 0; j < m_cache_assoc; j++) { + m_cache[i][j] = NULL; + m_locked[i][j] = -1; + } + } + } + + CacheMemory::~CacheMemory() + { + if(m_replacementPolicy_ptr != NULL) + delete m_replacementPolicy_ptr; + delete m_profiler_ptr; + for (int i = 0; i < m_cache_num_sets; i++) { + for (int j = 0; j < m_cache_assoc; j++) { + delete m_cache[i][j]; + } + } + } + + int -CacheMemory::numberOfLastLevelCaches() ++CacheMemory::numberOfLastLevelCaches() + { + return m_num_last_level_caches; + } + + + void CacheMemory::printConfig(ostream& out) + { + out << "Cache config: " << m_cache_name << endl; + if (m_controller != NULL) + out << " controller: " << m_controller->getName() << endl; + out << " cache_associativity: " << m_cache_assoc << endl; + out << " num_cache_sets_bits: " << m_cache_num_set_bits << endl; + const int cache_num_sets = 1 << m_cache_num_set_bits; + out << " num_cache_sets: " << cache_num_sets << endl; + out << " cache_set_size_bytes: " << cache_num_sets * RubySystem::getBlockSizeBytes() << endl; + out << " cache_set_size_Kbytes: " + << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<10) << endl; + out << " cache_set_size_Mbytes: " + << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<20) << endl; + out << " cache_size_bytes: " + << cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc << endl; + out << " cache_size_Kbytes: " + << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<10) << endl; + out << " cache_size_Mbytes: " + << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<20) << endl; + } + + // PRIVATE METHODS + + // convert a Address to its location in the cache + Index CacheMemory::addressToCacheSet(const Address& address) const + { + assert(address == line_address(address)); + return address.bitSelect(RubySystem::getBlockSizeBits(), RubySystem::getBlockSizeBits() + m_cache_num_set_bits-1); + } + + // Given a cache index: returns the index of the tag in a set. + // returns -1 if the tag is not found. + int CacheMemory::findTagInSet(Index cacheSet, const Address& tag) const + { + assert(tag == line_address(tag)); + // search the set for the tags - for (int i=0; i < m_cache_assoc; i++) { - if ((m_cache[cacheSet][i] != NULL) && - (m_cache[cacheSet][i]->m_Address == tag) && - (m_cache[cacheSet][i]->m_Permission != AccessPermission_NotPresent)) { - return i; - } - } ++ m5::hash_map::const_iterator it = m_tag_index.find(tag); ++ if (it != m_tag_index.end()) ++ if (m_cache[cacheSet][it->second]->m_Permission != AccessPermission_NotPresent) ++ return it->second; + return -1; // Not found + } + + // Given a cache index: returns the index of the tag in a set. + // returns -1 if the tag is not found. + int CacheMemory::findTagInSetIgnorePermissions(Index cacheSet, const Address& tag) const + { + assert(tag == line_address(tag)); + // search the set for the tags - for (int i=0; i < m_cache_assoc; i++) { - if (m_cache[cacheSet][i] != NULL && m_cache[cacheSet][i]->m_Address == tag) - return i; - } ++ m5::hash_map::const_iterator it = m_tag_index.find(tag); ++ if (it != m_tag_index.end()) ++ return it->second; + return -1; // Not found + } + + // PUBLIC METHODS + bool CacheMemory::tryCacheAccess(const Address& address, + CacheRequestType type, + DataBlock*& data_ptr) + { + assert(address == line_address(address)); + DEBUG_EXPR(CACHE_COMP, HighPrio, address); + Index cacheSet = addressToCacheSet(address); + int loc = findTagInSet(cacheSet, address); + if(loc != -1){ // Do we even have a tag match? + AbstractCacheEntry* entry = m_cache[cacheSet][loc]; + m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime()); + data_ptr = &(entry->getDataBlk()); + + if(entry->m_Permission == AccessPermission_Read_Write) { + return true; + } + if ((entry->m_Permission == AccessPermission_Read_Only) && + (type == CacheRequestType_LD || type == CacheRequestType_IFETCH)) { + return true; + } + // The line must not be accessible + } + data_ptr = NULL; + return false; + } + + bool CacheMemory::testCacheAccess(const Address& address, + CacheRequestType type, + DataBlock*& data_ptr) + { + assert(address == line_address(address)); + DEBUG_EXPR(CACHE_COMP, HighPrio, address); + Index cacheSet = addressToCacheSet(address); + int loc = findTagInSet(cacheSet, address); + if(loc != -1){ // Do we even have a tag match? + AbstractCacheEntry* entry = m_cache[cacheSet][loc]; + m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime()); + data_ptr = &(entry->getDataBlk()); + + return (m_cache[cacheSet][loc]->m_Permission != AccessPermission_NotPresent); + } + data_ptr = NULL; + return false; + } + + // tests to see if an address is present in the cache + bool CacheMemory::isTagPresent(const Address& address) const + { + assert(address == line_address(address)); + Index cacheSet = addressToCacheSet(address); + int location = findTagInSet(cacheSet, address); + + if (location == -1) { + // We didn't find the tag + DEBUG_EXPR(CACHE_COMP, LowPrio, address); + DEBUG_MSG(CACHE_COMP, LowPrio, "No tag match"); + return false; + } + DEBUG_EXPR(CACHE_COMP, LowPrio, address); + DEBUG_MSG(CACHE_COMP, LowPrio, "found"); + return true; + } + + // Returns true if there is: + // a) a tag match on this address or there is + // b) an unused line in the same cache "way" + bool CacheMemory::cacheAvail(const Address& address) const + { + assert(address == line_address(address)); + + Index cacheSet = addressToCacheSet(address); + + for (int i=0; i < m_cache_assoc; i++) { + AbstractCacheEntry* entry = m_cache[cacheSet][i]; + if (entry != NULL) { + if (entry->m_Address == address || // Already in the cache + entry->m_Permission == AccessPermission_NotPresent) { // We found an empty entry + return true; + } + } else { + return true; + } + } + return false; + } + + void CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry) + { + assert(address == line_address(address)); + assert(!isTagPresent(address)); + assert(cacheAvail(address)); + DEBUG_EXPR(CACHE_COMP, HighPrio, address); + + // Find the first open slot + Index cacheSet = addressToCacheSet(address); + for (int i=0; i < m_cache_assoc; i++) { + if (m_cache[cacheSet][i] == NULL || + m_cache[cacheSet][i]->m_Permission == AccessPermission_NotPresent) { + m_cache[cacheSet][i] = entry; // Init entry + m_cache[cacheSet][i]->m_Address = address; + m_cache[cacheSet][i]->m_Permission = AccessPermission_Invalid; + m_locked[cacheSet][i] = -1; ++ m_tag_index[address] = i; + + m_replacementPolicy_ptr->touch(cacheSet, i, g_eventQueue_ptr->getTime()); + + return; + } + } + ERROR_MSG("Allocate didn't find an available entry"); + } + + void CacheMemory::deallocate(const Address& address) + { + assert(address == line_address(address)); + assert(isTagPresent(address)); + DEBUG_EXPR(CACHE_COMP, HighPrio, address); + Index cacheSet = addressToCacheSet(address); + int location = findTagInSet(cacheSet, address); + if (location != -1){ + delete m_cache[cacheSet][location]; + m_cache[cacheSet][location] = NULL; + m_locked[cacheSet][location] = -1; ++ m_tag_index.erase(address); + } + } + + // Returns with the physical address of the conflicting cache line + Address CacheMemory::cacheProbe(const Address& address) const + { + assert(address == line_address(address)); + assert(!cacheAvail(address)); + + Index cacheSet = addressToCacheSet(address); + return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)]->m_Address; + } + + // looks an address up in the cache + AbstractCacheEntry& CacheMemory::lookup(const Address& address) + { + assert(address == line_address(address)); + Index cacheSet = addressToCacheSet(address); + int loc = findTagInSet(cacheSet, address); + assert(loc != -1); + return *m_cache[cacheSet][loc]; + } + + // looks an address up in the cache + const AbstractCacheEntry& CacheMemory::lookup(const Address& address) const + { + assert(address == line_address(address)); + Index cacheSet = addressToCacheSet(address); + int loc = findTagInSet(cacheSet, address); + assert(loc != -1); + return *m_cache[cacheSet][loc]; + } + + AccessPermission CacheMemory::getPermission(const Address& address) const + { + assert(address == line_address(address)); + return lookup(address).m_Permission; + } + + void CacheMemory::changePermission(const Address& address, AccessPermission new_perm) + { + assert(address == line_address(address)); + lookup(address).m_Permission = new_perm; + Index cacheSet = addressToCacheSet(address); + int loc = findTagInSet(cacheSet, address); + m_locked[cacheSet][loc] = -1; + assert(getPermission(address) == new_perm); + } + + // Sets the most recently used bit for a cache block + void CacheMemory::setMRU(const Address& address) + { + Index cacheSet; + + cacheSet = addressToCacheSet(address); + m_replacementPolicy_ptr->touch(cacheSet, + findTagInSet(cacheSet, address), + g_eventQueue_ptr->getTime()); + } + + void CacheMemory::profileMiss(const CacheMsg & msg) + { + m_profiler_ptr->addStatSample(msg.getType(), msg.getAccessMode(), + msg.getSize(), msg.getPrefetch()); + } + + void CacheMemory::recordCacheContents(CacheRecorder& tr) const + { + for (int i = 0; i < m_cache_num_sets; i++) { + for (int j = 0; j < m_cache_assoc; j++) { + AccessPermission perm = m_cache[i][j]->m_Permission; + CacheRequestType request_type = CacheRequestType_NULL; + if (perm == AccessPermission_Read_Only) { + if (m_is_instruction_only_cache) { + request_type = CacheRequestType_IFETCH; + } else { + request_type = CacheRequestType_LD; + } + } else if (perm == AccessPermission_Read_Write) { + request_type = CacheRequestType_ST; + } + + if (request_type != CacheRequestType_NULL) { + // tr.addRecord(m_chip_ptr->getID(), m_cache[i][j].m_Address, + // Address(0), request_type, m_replacementPolicy_ptr->getLastAccess(i, j)); + } + } + } + } + + void CacheMemory::print(ostream& out) const + { + out << "Cache dump: " << m_cache_name << endl; + for (int i = 0; i < m_cache_num_sets; i++) { + for (int j = 0; j < m_cache_assoc; j++) { + if (m_cache[i][j] != NULL) { + out << " Index: " << i + << " way: " << j + << " entry: " << *m_cache[i][j] << endl; + } else { + out << " Index: " << i + << " way: " << j + << " entry: NULL" << endl; + } + } + } + } + + void CacheMemory::printData(ostream& out) const + { + out << "printData() not supported" << endl; + } + + void CacheMemory::clearStats() const + { + m_profiler_ptr->clearStats(); + } + + void CacheMemory::printStats(ostream& out) const + { + m_profiler_ptr->printStats(out); + } + + void CacheMemory::getMemoryValue(const Address& addr, char* value, + unsigned int size_in_bytes ){ + AbstractCacheEntry& entry = lookup(line_address(addr)); + unsigned int startByte = addr.getAddress() - line_address(addr).getAddress(); + for(unsigned int i=0; i 0); + for(unsigned int i=0; i class CacheMemory { @@@ -104,6 -106,6 +105,8 @@@ public AccessPermission getPermission(const Address& address) const; void changePermission(const Address& address, AccessPermission new_perm); ++ static int numberOfLastLevelCaches(); ++ int getLatency() const { return m_latency; } // Hook for checkpointing the contents of the cache @@@ -168,466 -169,10 +171,12 @@@ private int m_cache_num_set_bits; int m_cache_assoc; + static Vector< CacheMemory* > m_all_caches; - }; ++ + static int m_num_last_level_caches; + static MachineType m_last_level_machine_type; - static Vector< CacheMemory* > m_all_caches; + - // Output operator declaration - //ostream& operator<<(ostream& out, const CacheMemory& obj); - - // ******************* Definitions ******************* - - // Output operator definition - inline - ostream& operator<<(ostream& out, const CacheMemory& obj) - { - obj.print(out); - out << flush; - return out; - } - - - // **************************************************************** - - inline - CacheMemory::CacheMemory(const string & name) - : m_cache_name(name) - { - m_profiler_ptr = new CacheProfiler(name); - } - - inline - void CacheMemory::init(const vector & argv) - { - int cache_size = 0; - string policy; - - m_controller = NULL; - for (uint32 i=0; igetName() << endl; - out << " cache_associativity: " << m_cache_assoc << endl; - out << " num_cache_sets_bits: " << m_cache_num_set_bits << endl; - const int cache_num_sets = 1 << m_cache_num_set_bits; - out << " num_cache_sets: " << cache_num_sets << endl; - out << " cache_set_size_bytes: " << cache_num_sets * RubySystem::getBlockSizeBytes() << endl; - out << " cache_set_size_Kbytes: " - << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<10) << endl; - out << " cache_set_size_Mbytes: " - << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<20) << endl; - out << " cache_size_bytes: " - << cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc << endl; - out << " cache_size_Kbytes: " - << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<10) << endl; - out << " cache_size_Mbytes: " - << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<20) << endl; - } - - // PRIVATE METHODS - - // convert a Address to its location in the cache - inline - Index CacheMemory::addressToCacheSet(const Address& address) const - { - assert(address == line_address(address)); - return address.bitSelect(RubySystem::getBlockSizeBits(), RubySystem::getBlockSizeBits() + m_cache_num_set_bits-1); - } - - // Given a cache index: returns the index of the tag in a set. - // returns -1 if the tag is not found. - inline - int CacheMemory::findTagInSet(Index cacheSet, const Address& tag) const - { - assert(tag == line_address(tag)); - // search the set for the tags - m5::hash_map::const_iterator it = m_tag_index.find(tag); - if (it != m_tag_index.end()) - if (m_cache[cacheSet][it->second]->m_Permission != AccessPermission_NotPresent) - return it->second; - return -1; // Not found - } - - // Given a cache index: returns the index of the tag in a set. - // returns -1 if the tag is not found. - inline - int CacheMemory::findTagInSetIgnorePermissions(Index cacheSet, const Address& tag) const - { - assert(tag == line_address(tag)); - // search the set for the tags - m5::hash_map::const_iterator it = m_tag_index.find(tag); - if (it != m_tag_index.end()) - return it->second; - return -1; // Not found - } - - // PUBLIC METHODS - inline - bool CacheMemory::tryCacheAccess(const Address& address, - CacheRequestType type, - DataBlock*& data_ptr) - { - assert(address == line_address(address)); - DEBUG_EXPR(CACHE_COMP, HighPrio, address); - Index cacheSet = addressToCacheSet(address); - int loc = findTagInSet(cacheSet, address); - if(loc != -1){ // Do we even have a tag match? - AbstractCacheEntry* entry = m_cache[cacheSet][loc]; - m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime()); - data_ptr = &(entry->getDataBlk()); - - if(entry->m_Permission == AccessPermission_Read_Write) { - return true; - } - if ((entry->m_Permission == AccessPermission_Read_Only) && - (type == CacheRequestType_LD || type == CacheRequestType_IFETCH)) { - return true; - } - // The line must not be accessible - } - data_ptr = NULL; - return false; - } - - inline - bool CacheMemory::testCacheAccess(const Address& address, - CacheRequestType type, - DataBlock*& data_ptr) - { - assert(address == line_address(address)); - DEBUG_EXPR(CACHE_COMP, HighPrio, address); - Index cacheSet = addressToCacheSet(address); - int loc = findTagInSet(cacheSet, address); - if(loc != -1){ // Do we even have a tag match? - AbstractCacheEntry* entry = m_cache[cacheSet][loc]; - m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime()); - data_ptr = &(entry->getDataBlk()); - - return (m_cache[cacheSet][loc]->m_Permission != AccessPermission_NotPresent); - } - data_ptr = NULL; - return false; - } - - // tests to see if an address is present in the cache - inline - bool CacheMemory::isTagPresent(const Address& address) const - { - assert(address == line_address(address)); - Index cacheSet = addressToCacheSet(address); - int location = findTagInSet(cacheSet, address); - - if (location == -1) { - // We didn't find the tag - DEBUG_EXPR(CACHE_COMP, LowPrio, address); - DEBUG_MSG(CACHE_COMP, LowPrio, "No tag match"); - return false; - } - DEBUG_EXPR(CACHE_COMP, LowPrio, address); - DEBUG_MSG(CACHE_COMP, LowPrio, "found"); - return true; - } - - // Returns true if there is: - // a) a tag match on this address or there is - // b) an unused line in the same cache "way" - inline - bool CacheMemory::cacheAvail(const Address& address) const - { - assert(address == line_address(address)); - - Index cacheSet = addressToCacheSet(address); - - for (int i=0; i < m_cache_assoc; i++) { - AbstractCacheEntry* entry = m_cache[cacheSet][i]; - if (entry != NULL) { - if (entry->m_Address == address || // Already in the cache - entry->m_Permission == AccessPermission_NotPresent) { // We found an empty entry - return true; - } - } else { - return true; - } - } - return false; - } - - inline - void CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry) - { - assert(address == line_address(address)); - assert(!isTagPresent(address)); - assert(cacheAvail(address)); - DEBUG_EXPR(CACHE_COMP, HighPrio, address); - - // Find the first open slot - Index cacheSet = addressToCacheSet(address); - for (int i=0; i < m_cache_assoc; i++) { - if (m_cache[cacheSet][i] == NULL || - m_cache[cacheSet][i]->m_Permission == AccessPermission_NotPresent) { - m_cache[cacheSet][i] = entry; // Init entry - m_cache[cacheSet][i]->m_Address = address; - m_cache[cacheSet][i]->m_Permission = AccessPermission_Invalid; - m_locked[cacheSet][i] = -1; - m_tag_index[address] = i; - - m_replacementPolicy_ptr->touch(cacheSet, i, g_eventQueue_ptr->getTime()); - - return; - } - } - ERROR_MSG("Allocate didn't find an available entry"); - } - - inline - void CacheMemory::deallocate(const Address& address) - { - assert(address == line_address(address)); - assert(isTagPresent(address)); - DEBUG_EXPR(CACHE_COMP, HighPrio, address); - Index cacheSet = addressToCacheSet(address); - int location = findTagInSet(cacheSet, address); - if (location != -1){ - delete m_cache[cacheSet][location]; - m_cache[cacheSet][location] = NULL; - m_locked[cacheSet][location] = -1; - m_tag_index.erase(address); - } - } - - // Returns with the physical address of the conflicting cache line - inline - Address CacheMemory::cacheProbe(const Address& address) const - { - assert(address == line_address(address)); - assert(!cacheAvail(address)); - - Index cacheSet = addressToCacheSet(address); - return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)]->m_Address; - } - - // looks an address up in the cache - inline - AbstractCacheEntry& CacheMemory::lookup(const Address& address) - { - assert(address == line_address(address)); - Index cacheSet = addressToCacheSet(address); - int loc = findTagInSet(cacheSet, address); - assert(loc != -1); - return *m_cache[cacheSet][loc]; - } - - // looks an address up in the cache - inline - const AbstractCacheEntry& CacheMemory::lookup(const Address& address) const - { - assert(address == line_address(address)); - Index cacheSet = addressToCacheSet(address); - int loc = findTagInSet(cacheSet, address); - assert(loc != -1); - return *m_cache[cacheSet][loc]; - } - - inline - AccessPermission CacheMemory::getPermission(const Address& address) const - { - assert(address == line_address(address)); - return lookup(address).m_Permission; - } - - inline - void CacheMemory::changePermission(const Address& address, AccessPermission new_perm) - { - assert(address == line_address(address)); - lookup(address).m_Permission = new_perm; - Index cacheSet = addressToCacheSet(address); - int loc = findTagInSet(cacheSet, address); - m_locked[cacheSet][loc] = -1; - assert(getPermission(address) == new_perm); - } - - // Sets the most recently used bit for a cache block - inline - void CacheMemory::setMRU(const Address& address) - { - Index cacheSet; - - cacheSet = addressToCacheSet(address); - m_replacementPolicy_ptr->touch(cacheSet, - findTagInSet(cacheSet, address), - g_eventQueue_ptr->getTime()); - } - - inline - void CacheMemory::profileMiss(const CacheMsg & msg) - { - m_profiler_ptr->addStatSample(msg.getType(), msg.getAccessMode(), - msg.getSize(), msg.getPrefetch()); - } - - inline - void CacheMemory::recordCacheContents(CacheRecorder& tr) const - { - for (int i = 0; i < m_cache_num_sets; i++) { - for (int j = 0; j < m_cache_assoc; j++) { - AccessPermission perm = m_cache[i][j]->m_Permission; - CacheRequestType request_type = CacheRequestType_NULL; - if (perm == AccessPermission_Read_Only) { - if (m_is_instruction_only_cache) { - request_type = CacheRequestType_IFETCH; - } else { - request_type = CacheRequestType_LD; - } - } else if (perm == AccessPermission_Read_Write) { - request_type = CacheRequestType_ST; - } - - if (request_type != CacheRequestType_NULL) { - // tr.addRecord(m_chip_ptr->getID(), m_cache[i][j].m_Address, - // Address(0), request_type, m_replacementPolicy_ptr->getLastAccess(i, j)); - } - } - } - } - - inline - void CacheMemory::print(ostream& out) const - { - out << "Cache dump: " << m_cache_name << endl; - for (int i = 0; i < m_cache_num_sets; i++) { - for (int j = 0; j < m_cache_assoc; j++) { - if (m_cache[i][j] != NULL) { - out << " Index: " << i - << " way: " << j - << " entry: " << *m_cache[i][j] << endl; - } else { - out << " Index: " << i - << " way: " << j - << " entry: NULL" << endl; - } - } - } - } - - inline - void CacheMemory::printData(ostream& out) const - { - out << "printData() not supported" << endl; - } - - inline void CacheMemory::clearStats() const - { - m_profiler_ptr->clearStats(); - } - - inline - void CacheMemory::printStats(ostream& out) const - { - m_profiler_ptr->printStats(out); - } - - inline - void CacheMemory::getMemoryValue(const Address& addr, char* value, - unsigned int size_in_bytes ){ - AbstractCacheEntry& entry = lookup(line_address(addr)); - unsigned int startByte = addr.getAddress() - line_address(addr).getAddress(); - for(unsigned int i=0; i 0); - for(unsigned int i=0; i & argv); + MessageBuffer* getMandatoryQueue() const; + const int & getVersion() const; + const string toString() const; + const string getName() const; + const MachineType getMachineType() const; + void print(ostream& out) const; + void printConfig(ostream& out) const; + void wakeup(); + void set_atomic(Address addr); - void started_writes(); - void clear_atomic(); ++ void clear_atomic(Address addr); ++ void reset_atomics(); + void printStats(ostream& out) const { s_profiler.dumpStats(out); } + void clearStats() { s_profiler.clearStats(); } + private: + ''') + + code.indent() + # added by SS + for param in self.config_parameters: + code('int m_${{param.ident}};') + + if self.ident == "L1Cache": + code(''' + int servicing_atomic; -bool started_receiving_writes; + Address locked_read_request1; + Address locked_read_request2; + Address locked_read_request3; + Address locked_read_request4; + int read_counter; + ''') + + code(''' + int m_number_of_TBEs; + + TransitionResult doTransition(${ident}_Event event, ${ident}_State state, const Address& addr); // in ${ident}_Transitions.cc + TransitionResult doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr); // in ${ident}_Transitions.cc + string m_name; + int m_transitions_per_cycle; + int m_buffer_size; + int m_recycle_latency; + map< string, string > m_cfg; + NodeID m_version; + Network* m_net_ptr; + MachineID m_machineID; + ${ident}_Profiler s_profiler; + static int m_num_controllers; + // Internal functions + ''') + + for func in self.functions: + proto = func.prototype + if proto: + code('$proto') + + code(''' + + // Actions + ''') + for action in self.actions.itervalues(): + code('/** \\brief ${{action.desc}} */') + code('void ${{action.ident}}(const Address& addr);') + + # the controller internal variables + code(''' + + // Object + ''') + for var in self.objects: + th = var.get("template_hack", "") + code('${{var.type.c_ident}}$th* m_${{var.c_ident}}_ptr;') + + if var.type.ident == "MessageBuffer": + self.message_buffer_names.append("m_%s_ptr" % var.c_ident) + + code.dedent() + code('};') + code('#endif // ${ident}_CONTROLLER_H') + code.write(path, '%s.hh' % c_ident) + + def printControllerCC(self, path): + '''Output the actions for performing the actions''' + + code = code_formatter() + ident = self.ident + c_ident = "%s_Controller" % self.ident + + code(''' + /** \\file $ident.cc + * + * Auto generated C++ code started by $__file__:$__line__ + * Created by slicc definition of Module "${{self.short}}" + */ + + #include "mem/ruby/common/Global.hh" + #include "mem/ruby/slicc_interface/RubySlicc_includes.hh" + #include "mem/protocol/${ident}_Controller.hh" + #include "mem/protocol/${ident}_State.hh" + #include "mem/protocol/${ident}_Event.hh" + #include "mem/protocol/Types.hh" + #include "mem/ruby/system/System.hh" + ''') + + # include object classes + seen_types = set() + for var in self.objects: + if var.type.ident not in seen_types and not var.type.isPrimitive: + code('#include "mem/protocol/${{var.type.c_ident}}.hh"') + seen_types.add(var.type.ident) + + code(''' + int $c_ident::m_num_controllers = 0; + + stringstream ${ident}_transitionComment; + #define APPEND_TRANSITION_COMMENT(str) (${ident}_transitionComment << str) + /** \\brief constructor */ + $c_ident::$c_ident(const string &name) + : m_name(name) + { + ''') + code.indent() + if self.ident == "L1Cache": + code(''' + servicing_atomic = 0; -started_receiving_writes = false; + locked_read_request1 = Address(-1); + locked_read_request2 = Address(-1); + locked_read_request3 = Address(-1); + locked_read_request4 = Address(-1); + read_counter = 0; + ''') + + code('m_num_controllers++;') + for var in self.objects: + if var.ident.find("mandatoryQueue") >= 0: + code('m_${{var.c_ident}}_ptr = new ${{var.type.c_ident}}();') + + code.dedent() + code(''' + } + + void $c_ident::init(Network *net_ptr, const vector &argv) + { + for (size_t i = 0; i < argv.size(); i += 2) { + if (argv[i] == "version") + m_version = atoi(argv[i+1].c_str()); + else if (argv[i] == "transitions_per_cycle") + m_transitions_per_cycle = atoi(argv[i+1].c_str()); + else if (argv[i] == "buffer_size") + m_buffer_size = atoi(argv[i+1].c_str()); + else if (argv[i] == "recycle_latency") + m_recycle_latency = atoi(argv[i+1].c_str()); + else if (argv[i] == "number_of_TBEs") + m_number_of_TBEs = atoi(argv[i+1].c_str()); + ''') + + code.indent() + code.indent() + for param in self.config_parameters: + code('else if (argv[i] == "${{param.name}}")') + if param.type_ast.type.ident == "int": + code(' m_${{param.name}} = atoi(argv[i+1].c_str());') + elif param.type_ast.type.ident == "bool": + code(' m_${{param.name}} = string_to_bool(argv[i+1]);') + else: + self.error("only int and bool parameters are "\ + "currently supported") + code.dedent() + code.dedent() + code(''' + } + + m_net_ptr = net_ptr; + m_machineID.type = MachineType_${ident}; + m_machineID.num = m_version; + for (size_t i = 0; i < argv.size(); i += 2) { + if (argv[i] != "version") + m_cfg[argv[i]] = argv[i+1]; + } + + // Objects + s_profiler.setVersion(m_version); + ''') + + code.indent() + for var in self.objects: + vtype = var.type + vid = "m_%s_ptr" % var.c_ident + if "network" not in var: + # Not a network port object + if "primitive" in vtype: + code('$vid = new ${{vtype.c_ident}};') + if "default" in var: + code('(*$vid) = ${{var["default"]}};') + else: + # Normal Object + # added by SS + if "factory" in var: + code('$vid = ${{var["factory"]}};') + elif var.ident.find("mandatoryQueue") < 0: + th = var.get("template_hack", "") + expr = "%s = new %s%s" % (vid, vtype.c_ident, th) + + args = "" + if "non_obj" not in vtype and not vtype.isEnumeration: + if expr.find("TBETable") >= 0: + args = "m_number_of_TBEs" + else: + args = var.get("constructor_hack", "") + args = "(%s)" % args + + code('$expr$args;') + else: + code(';') + + code('assert($vid != NULL);') + + if "default" in var: + code('(*$vid) = ${{var["default"]}}; // Object default') + elif "default" in vtype: + code('(*$vid) = ${{vtype["default"]}}; // Type ${{vtype.ident}} default') + + # Set ordering + if "ordered" in var and "trigger_queue" not in var: + # A buffer + code('$vid->setOrdering(${{var["ordered"]}});') + + # Set randomization + if "random" in var: + # A buffer + code('$vid->setRandomization(${{var["random"]}});') + + # Set Priority + if vtype.isBuffer and \ + "rank" in var and "trigger_queue" not in var: + code('$vid->setPriority(${{var["rank"]}});') + else: + # Network port object + network = var["network"] + ordered = var["ordered"] + vnet = var["virtual_network"] + + assert var.machine is not None + code(''' + $vid = m_net_ptr->get${network}NetQueue(m_version+MachineType_base_number(string_to_MachineType("${{var.machine.ident}}")), $ordered, $vnet); + ''') + + code('assert($vid != NULL);') + + # Set ordering + if "ordered" in var: + # A buffer + code('$vid->setOrdering(${{var["ordered"]}});') + + # Set randomization + if "random" in var: + # A buffer + code('$vid->setRandomization(${{var["random"]}})') + + # Set Priority + if "rank" in var: + code('$vid->setPriority(${{var["rank"]}})') + + # Set buffer size + if vtype.isBuffer: + code(''' + if (m_buffer_size > 0) { + $vid->setSize(m_buffer_size); + } + ''') + + # set description (may be overriden later by port def) + code('$vid->setDescription("[Version " + int_to_string(m_version) + ", ${ident}, name=${{var.c_ident}}]");') + + # Set the queue consumers + code.insert_newline() + for port in self.in_ports: + code('${{port.code}}.setConsumer(this);') + + # Set the queue descriptions + code.insert_newline() + for port in self.in_ports: + code('${{port.code}}.setDescription("[Version " + int_to_string(m_version) + ", $ident, $port]");') + + # Initialize the transition profiling + code.insert_newline() + for trans in self.transitions: + # Figure out if we stall + stall = False + for action in trans.actions: + if action.ident == "z_stall": + stall = True + + # Only possible if it is not a 'z' case + if not stall: + state = "%s_State_%s" % (self.ident, trans.state.ident) + event = "%s_Event_%s" % (self.ident, trans.event.ident) + code('s_profiler.possibleTransition($state, $event);') + + # added by SS to initialize recycle_latency of message buffers + for buf in self.message_buffer_names: + code("$buf->setRecycleLatency(m_recycle_latency);") + + code.dedent() + code('}') + + has_mandatory_q = False + for port in self.in_ports: + if port.code.find("mandatoryQueue_ptr") >= 0: + has_mandatory_q = True + + if has_mandatory_q: + mq_ident = "m_%s_mandatoryQueue_ptr" % self.ident + else: + mq_ident = "NULL" + + code(''' + int $c_ident::getNumControllers() { + return m_num_controllers; + } + + MessageBuffer* $c_ident::getMandatoryQueue() const { + return $mq_ident; + } + + const int & $c_ident::getVersion() const{ + return m_version; + } + + const string $c_ident::toString() const{ + return "$c_ident"; + } + + const string $c_ident::getName() const{ + return m_name; + } + const MachineType $c_ident::getMachineType() const{ + return MachineType_${ident}; + } + + void $c_ident::print(ostream& out) const { out << "[$c_ident " << m_version << "]"; } + + void $c_ident::printConfig(ostream& out) const { + out << "$c_ident config: " << m_name << endl; + out << " version: " << m_version << endl; + for (map::const_iterator it = m_cfg.begin(); it != m_cfg.end(); it++) { + out << " " << (*it).first << ": " << (*it).second << endl; + } + } + + // Actions + ''') + + for action in self.actions.itervalues(): + if "c_code" not in action: + continue + + code(''' + /** \\brief ${{action.desc}} */ + void $c_ident::${{action.ident}}(const Address& addr) + { + DEBUG_MSG(GENERATED_COMP, HighPrio, "executing"); + ${{action["c_code"]}} + } + + ''') + code.write(path, "%s.cc" % c_ident) + + def printCWakeup(self, path): + '''Output the wakeup loop for the events''' + + code = code_formatter() + ident = self.ident + + code(''' + // Auto generated C++ code started by $__file__:$__line__ + // ${ident}: ${{self.short}} + + #include "mem/ruby/common/Global.hh" + #include "mem/ruby/slicc_interface/RubySlicc_includes.hh" + #include "mem/protocol/${ident}_Controller.hh" + #include "mem/protocol/${ident}_State.hh" + #include "mem/protocol/${ident}_Event.hh" + #include "mem/protocol/Types.hh" + #include "mem/ruby/system/System.hh" + + void ${ident}_Controller::wakeup() + { + + int counter = 0; + while (true) { + // Some cases will put us into an infinite loop without this limit + assert(counter <= m_transitions_per_cycle); + if (counter == m_transitions_per_cycle) { + g_system_ptr->getProfiler()->controllerBusy(m_machineID); // Count how often we\'re fully utilized + g_eventQueue_ptr->scheduleEvent(this, 1); // Wakeup in another cycle and try again + break; + } + ''') + + code.indent() + code.indent() + + # InPorts + # + # Find the position of the mandatory queue in the vector so + # that we can print it out first + + mandatory_q = None + if self.ident == "L1Cache": + for i,port in enumerate(self.in_ports): + assert "c_code_in_port" in port + if str(port).find("mandatoryQueue_in") >= 0: + assert mandatory_q is None + mandatory_q = port + + assert mandatory_q is not None + + # print out the mandatory queue here + port = mandatory_q + code('// ${ident}InPort $port') + output = port["c_code_in_port"] + - pos = output.find("TransitionResult result = doTransition((L1Cache_mandatory_request_type_to_event(((*in_msg_ptr)).m_Type)), L1Cache_getState(addr), addr);") - assert pos >= 0 - atomics_string = ''' -if ((((*in_msg_ptr)).m_Type) == CacheRequestType_ATOMIC) { - if (servicing_atomic == 0) { - if (locked_read_request1 == Address(-1)) { - assert(read_counter == 0); - locked_read_request1 = addr; - assert(read_counter == 0); - read_counter++; - } - else if (addr == locked_read_request1) { - ; // do nothing - } - else { - assert(0); // should never be here if servicing one request at a time - } - } - else if (!started_receiving_writes) { - if (servicing_atomic == 1) { - if (locked_read_request2 == Address(-1)) { - assert(locked_read_request1 != Address(-1)); - assert(read_counter == 1); - locked_read_request2 = addr; - assert(read_counter == 1); - read_counter++; - } - else if (addr == locked_read_request2) { - ; // do nothing - } - else { - assert(0); // should never be here if servicing one request at a time - } - } - else if (servicing_atomic == 2) { - if (locked_read_request3 == Address(-1)) { - assert(locked_read_request1 != Address(-1)); - assert(locked_read_request2 != Address(-1)); - assert(read_counter == 1); - locked_read_request3 = addr; - assert(read_counter == 2); - read_counter++; - } - else if (addr == locked_read_request3) { - ; // do nothing - } - else { - assert(0); // should never be here if servicing one request at a time - } - } - else if (servicing_atomic == 3) { - if (locked_read_request4 == Address(-1)) { - assert(locked_read_request1 != Address(-1)); - assert(locked_read_request2 != Address(-1)); - assert(locked_read_request3 != Address(-1)); - assert(read_counter == 1); - locked_read_request4 = addr; - assert(read_counter == 3); - read_counter++; - } - else if (addr == locked_read_request4) { - ; // do nothing - } - else { - assert(0); // should never be here if servicing one request at a time - } - } - else { - assert(0); - } - } -} -else { - if (servicing_atomic > 0) { - // reset - servicing_atomic = 0; - read_counter = 0; - started_receiving_writes = false; - locked_read_request1 = Address(-1); - locked_read_request2 = Address(-1); - locked_read_request3 = Address(-1); - locked_read_request4 = Address(-1); - } -} -''' - - output = output[:pos] + atomics_string + output[pos:] + code('$output') + + for port in self.in_ports: + # don't print out mandatory queue twice + if port == mandatory_q: + continue + + if ident == "L1Cache": - if str(port).find("forwardRequestNetwork_in") >= 0: ++ if (str(port).find("forwardRequestNetwork_in") >= 0 or str(port).find("requestNetwork_in") >= 0 or str(port).find("requestIntraChipL1Network_in") >= 0): + code(''' + bool postpone = false; + if ((((*m_L1Cache_forwardToCache_ptr)).isReady())) { + const RequestMsg* in_msg_ptr; + in_msg_ptr = dynamic_cast(((*m_L1Cache_forwardToCache_ptr)).peek()); - if ((((servicing_atomic == 1) && (locked_read_request1 == ((*in_msg_ptr)).m_Address)) || - ((servicing_atomic == 2) && (locked_read_request1 == ((*in_msg_ptr)).m_Address || locked_read_request2 == ((*in_msg_ptr)).m_Address)) || - ((servicing_atomic == 3) && (locked_read_request1 == ((*in_msg_ptr)).m_Address || locked_read_request2 == ((*in_msg_ptr)).m_Address || locked_read_request3 == ((*in_msg_ptr)).m_Address)) || - ((servicing_atomic == 4) && (locked_read_request1 == ((*in_msg_ptr)).m_Address || locked_read_request2 == ((*in_msg_ptr)).m_Address || locked_read_request3 == ((*in_msg_ptr)).m_Address || locked_read_request1 == ((*in_msg_ptr)).m_Address)))) { - postpone = true; ++ if ((((servicing_atomic > 0) && (locked_read_request1 == ((*in_msg_ptr)).m_Address || locked_read_request2 == ((*in_msg_ptr)).m_Address || locked_read_request3 == ((*in_msg_ptr)).m_Address || locked_read_request1 == ((*in_msg_ptr)).m_Address)))) { ++ postpone = true; + } + } + if (!postpone) { + ''') + code.indent() + code('// ${ident}InPort $port') + code('${{port["c_code_in_port"]}}') + code.dedent() + + if ident == "L1Cache": - if str(port).find("forwardRequestNetwork_in") >= 0: ++ if (str(port).find("forwardRequestNetwork_in") >= 0 or str(port).find("requestNetwork_in") >= 0 or str(port).find("requestIntraChipL1Network_in") >= 0): + code.dedent() + code('}') + code.indent() + code('') + + code.dedent() + code.dedent() + code(''' + break; // If we got this far, we have nothing left todo + } + } + ''') + + if self.ident == "L1Cache": + code(''' + void ${ident}_Controller::set_atomic(Address addr) + { + servicing_atomic++; ++ switch (servicing_atomic) { ++ case(1): ++ assert(locked_read_request1 == Address(-1)); ++ locked_read_request1 = addr; ++ break; ++ case(2): ++ assert(locked_read_request2 == Address(-1)); ++ locked_read_request2 = addr; ++ break; ++ case(3): ++ assert(locked_read_request3 == Address(-1)); ++ locked_read_request3 = addr; ++ break; ++ case(4): ++ assert(locked_read_request4 == Address(-1)); ++ locked_read_request4 = addr; ++ break; ++ default: ++ assert(0); ++ ++ } + } + -void ${ident}_Controller::started_writes() ++void ${ident}_Controller::clear_atomic(Address addr) + { - started_receiving_writes = true; ++ ++ assert(servicing_atomic > 0); ++ if (addr == locked_read_request1) ++ locked_read_request1 = Address(-1); ++ else if (addr == locked_read_request2) ++ locked_read_request2 = Address(-1); ++ else if (addr == locked_read_request3) ++ locked_read_request3 = Address(-1); ++ else if (addr == locked_read_request4) ++ locked_read_request4 = Address(-1); ++ else ++ assert(0); ++ servicing_atomic--; ++ + } + -void ${ident}_Controller::clear_atomic() ++void ${ident}_Controller::reset_atomics() + { - assert(servicing_atomic > 0); - read_counter--; - servicing_atomic--; - if (read_counter == 0) { - servicing_atomic = 0; - started_receiving_writes = false; - locked_read_request1 = Address(-1); - locked_read_request2 = Address(-1); - locked_read_request3 = Address(-1); - locked_read_request4 = Address(-1); - } ++ ++ servicing_atomic = 0; ++ locked_read_request1 = Address(-1); ++ locked_read_request2 = Address(-1); ++ locked_read_request3 = Address(-1); ++ locked_read_request4 = Address(-1); ++ + } ++ + ''') + else: + code(''' -void ${ident}_Controller::started_writes() ++void ${ident}_Controller::reset_atomics() + { + assert(0); + } + + void ${ident}_Controller::set_atomic(Address addr) + { + assert(0); + } + -void ${ident}_Controller::clear_atomic() ++void ${ident}_Controller::clear_atomic(Address addr) + { + assert(0); + } + ''') + + + code.write(path, "%s_Wakeup.cc" % self.ident) + + def printCSwitch(self, path): + '''Output switch statement for transition table''' + + code = code_formatter() + ident = self.ident + + code(''' + // Auto generated C++ code started by $__file__:$__line__ + // ${ident}: ${{self.short}} + + #include "mem/ruby/common/Global.hh" + #include "mem/protocol/${ident}_Controller.hh" + #include "mem/protocol/${ident}_State.hh" + #include "mem/protocol/${ident}_Event.hh" + #include "mem/protocol/Types.hh" + #include "mem/ruby/system/System.hh" + + #define HASH_FUN(state, event) ((int(state)*${ident}_Event_NUM)+int(event)) + + #define GET_TRANSITION_COMMENT() (${ident}_transitionComment.str()) + #define CLEAR_TRANSITION_COMMENT() (${ident}_transitionComment.str("")) + + TransitionResult ${ident}_Controller::doTransition(${ident}_Event event, ${ident}_State state, const Address& addr + ) + { + ${ident}_State next_state = state; + + DEBUG_NEWLINE(GENERATED_COMP, MedPrio); + DEBUG_MSG(GENERATED_COMP, MedPrio, *this); + DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime()); + DEBUG_EXPR(GENERATED_COMP, MedPrio,state); + DEBUG_EXPR(GENERATED_COMP, MedPrio,event); + DEBUG_EXPR(GENERATED_COMP, MedPrio,addr); + + TransitionResult result = doTransitionWorker(event, state, next_state, addr); + + if (result == TransitionResult_Valid) { + DEBUG_EXPR(GENERATED_COMP, MedPrio, next_state); + DEBUG_NEWLINE(GENERATED_COMP, MedPrio); + s_profiler.countTransition(state, event); + if (Debug::getProtocolTrace()) { + g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, + ${ident}_State_to_string(state), + ${ident}_Event_to_string(event), + ${ident}_State_to_string(next_state), GET_TRANSITION_COMMENT()); + } + CLEAR_TRANSITION_COMMENT(); + ${ident}_setState(addr, next_state); + + } else if (result == TransitionResult_ResourceStall) { + if (Debug::getProtocolTrace()) { + g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, + ${ident}_State_to_string(state), + ${ident}_Event_to_string(event), + ${ident}_State_to_string(next_state), + "Resource Stall"); + } + } else if (result == TransitionResult_ProtocolStall) { + DEBUG_MSG(GENERATED_COMP, HighPrio, "stalling"); + DEBUG_NEWLINE(GENERATED_COMP, MedPrio); + if (Debug::getProtocolTrace()) { + g_system_ptr->getProfiler()->profileTransition("${ident}", m_version, addr, + ${ident}_State_to_string(state), + ${ident}_Event_to_string(event), + ${ident}_State_to_string(next_state), + "Protocol Stall"); + } + } + + return result; + } + + TransitionResult ${ident}_Controller::doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, const Address& addr + ) + { + switch(HASH_FUN(state, event)) { + ''') + + # This map will allow suppress generating duplicate code + cases = orderdict() + + for trans in self.transitions: + case_string = "%s_State_%s, %s_Event_%s" % \ + (self.ident, trans.state.ident, self.ident, trans.event.ident) + + case = code_formatter() + # Only set next_state if it changes + if trans.state != trans.nextState: + ns_ident = trans.nextState.ident + case('next_state = ${ident}_State_${ns_ident};') + + actions = trans.actions + + # Check for resources + case_sorter = [] + res = trans.resources + for key,val in res.iteritems(): + if key.type.ident != "DNUCAStopTable": + val = ''' + if (!%s.areNSlotsAvailable(%s)) { + return TransitionResult_ResourceStall; + } + ''' % (key.code, val) + case_sorter.append(val) + + + # Emit the code sequences in a sorted order. This makes the + # output deterministic (without this the output order can vary + # since Map's keys() on a vector of pointers is not deterministic + for c in sorted(case_sorter): + case("$c") + + # Figure out if we stall + stall = False + for action in actions: + if action.ident == "z_stall": + stall = True + break + + if stall: + case('return TransitionResult_ProtocolStall;') + else: + for action in actions: + case('${{action.ident}}(addr);') + case('return TransitionResult_Valid;') + + case = str(case) + + # Look to see if this transition code is unique. + if case not in cases: + cases[case] = [] + + cases[case].append(case_string) + + # Walk through all of the unique code blocks and spit out the + # corresponding case statement elements + for case,transitions in cases.iteritems(): + # Iterative over all the multiple transitions that share + # the same code + for trans in transitions: + code(' case HASH_FUN($trans):') + code(' {') + code(' $case') + code(' }') + + code(''' + default: + WARN_EXPR(m_version); + WARN_EXPR(g_eventQueue_ptr->getTime()); + WARN_EXPR(addr); + WARN_EXPR(event); + WARN_EXPR(state); + ERROR_MSG(\"Invalid transition\"); + } + return TransitionResult_Valid; + } + ''') + code.write(path, "%s_Transitions.cc" % self.ident) + + def printProfilerHH(self, path): + code = code_formatter() + ident = self.ident + + code(''' + // Auto generated C++ code started by $__file__:$__line__ + // ${ident}: ${{self.short}} + + #ifndef ${ident}_PROFILER_H + #define ${ident}_PROFILER_H + + #include "mem/ruby/common/Global.hh" + #include "mem/protocol/${ident}_State.hh" + #include "mem/protocol/${ident}_Event.hh" + + class ${ident}_Profiler { + public: + ${ident}_Profiler(); + void setVersion(int version); + void countTransition(${ident}_State state, ${ident}_Event event); + void possibleTransition(${ident}_State state, ${ident}_Event event); + void dumpStats(ostream& out) const; + void clearStats(); + + private: + int m_counters[${ident}_State_NUM][${ident}_Event_NUM]; + int m_event_counters[${ident}_Event_NUM]; + bool m_possible[${ident}_State_NUM][${ident}_Event_NUM]; + int m_version; + }; + + #endif // ${ident}_PROFILER_H + ''') + code.write(path, "%s_Profiler.hh" % self.ident) + + def printProfilerCC(self, path): + code = code_formatter() + ident = self.ident + + code(''' + // Auto generated C++ code started by $__file__:$__line__ + // ${ident}: ${{self.short}} + + #include "mem/protocol/${ident}_Profiler.hh" + + ${ident}_Profiler::${ident}_Profiler() + { + for (int state = 0; state < ${ident}_State_NUM; state++) { + for (int event = 0; event < ${ident}_Event_NUM; event++) { + m_possible[state][event] = false; + m_counters[state][event] = 0; + } + } + for (int event = 0; event < ${ident}_Event_NUM; event++) { + m_event_counters[event] = 0; + } + } + void ${ident}_Profiler::setVersion(int version) + { + m_version = version; + } + void ${ident}_Profiler::clearStats() + { + for (int state = 0; state < ${ident}_State_NUM; state++) { + for (int event = 0; event < ${ident}_Event_NUM; event++) { + m_counters[state][event] = 0; + } + } + + for (int event = 0; event < ${ident}_Event_NUM; event++) { + m_event_counters[event] = 0; + } + } + void ${ident}_Profiler::countTransition(${ident}_State state, ${ident}_Event event) + { + assert(m_possible[state][event]); + m_counters[state][event]++; + m_event_counters[event]++; + } + void ${ident}_Profiler::possibleTransition(${ident}_State state, ${ident}_Event event) + { + m_possible[state][event] = true; + } + void ${ident}_Profiler::dumpStats(ostream& out) const + { + out << " --- ${ident} " << m_version << " ---" << endl; + out << " - Event Counts -" << endl; + for (int event = 0; event < ${ident}_Event_NUM; event++) { + int count = m_event_counters[event]; + out << (${ident}_Event) event << " " << count << endl; + } + out << endl; + out << " - Transitions -" << endl; + for (int state = 0; state < ${ident}_State_NUM; state++) { + for (int event = 0; event < ${ident}_Event_NUM; event++) { + if (m_possible[state][event]) { + int count = m_counters[state][event]; + out << (${ident}_State) state << " " << (${ident}_Event) event << " " << count; + if (count == 0) { + out << " <-- "; + } + out << endl; + } + } + out << endl; + } + } + ''') + code.write(path, "%s_Profiler.cc" % self.ident) + + # ************************** + # ******* HTML Files ******* + # ************************** + def frameRef(self, click_href, click_target, over_href, over_target_num, + text): + code = code_formatter(fix_newlines=False) + code("""${{html.formatShorthand(text)}}""") + return str(code) + + def writeHTMLFiles(self, path): + # Create table with no row hilighted + self.printHTMLTransitions(path, None) + + # Generate transition tables + for state in self.states.itervalues(): + self.printHTMLTransitions(path, state) + + # Generate action descriptions + for action in self.actions.itervalues(): + name = "%s_action_%s.html" % (self.ident, action.ident) + code = html.createSymbol(action, "Action") + code.write(path, name) + + # Generate state descriptions + for state in self.states.itervalues(): + name = "%s_State_%s.html" % (self.ident, state.ident) + code = html.createSymbol(state, "State") + code.write(path, name) + + # Generate event descriptions + for event in self.events.itervalues(): + name = "%s_Event_%s.html" % (self.ident, event.ident) + code = html.createSymbol(event, "Event") + code.write(path, name) + + def printHTMLTransitions(self, path, active_state): + code = code_formatter() + + code(''' + + +

${{html.formatShorthand(self.short)}}: + ''') + code.indent() + for i,machine in enumerate(self.symtab.getAllType(StateMachine)): + mid = machine.ident + if i != 0: + extra = " - " + else: + extra = "" + if machine == self: + code('$extra$mid') + else: + code('$extra$mid') + code.dedent() + + code(""" +

+ + + + + """) + + for event in self.events.itervalues(): + href = "%s_Event_%s.html" % (self.ident, event.ident) + ref = self.frameRef(href, "Status", href, "1", event.short) + code('') + + code('') + # -- Body of table + for state in self.states.itervalues(): + # -- Each row + if state == active_state: + color = "yellow" + else: + color = "white" + + click = "%s_table_%s.html" % (self.ident, state.ident) + over = "%s_State_%s.html" % (self.ident, state.ident) + text = html.formatShorthand(state.short) + ref = self.frameRef(click, "Table", over, "1", state.short) + code(''' + + + ''') + + # -- One column for each event + for event in self.events.itervalues(): + trans = self.table.get((state,event), None) + if trans is None: + # This is the no transition case + if state == active_state: + color = "#C0C000" + else: + color = "lightgrey" + + code('') + continue + + next = trans.nextState + stall_action = False + + # -- Get the actions + for action in trans.actions: + if action.ident == "z_stall" or \ + action.ident == "zz_recycleMandatoryQueue": + stall_action = True + + # -- Print out "actions/next-state" + if stall_action: + if state == active_state: + color = "#C0C000" + else: + color = "lightgrey" + + elif active_state and next.ident == active_state.ident: + color = "aqua" + elif state == active_state: + color = "yellow" + else: + color = "white" + + fix = code.nofix() + code('\n") + code.fix(fix) + + # -- Each row + if state == active_state: + color = "yellow" + else: + color = "white" + + click = "%s_table_%s.html" % (self.ident, state.ident) + over = "%s_State_%s.html" % (self.ident, state.ident) + ref = self.frameRef(click, "Table", over, "1", state.short) + code(''' + + + ''') + code(''' + + + ''') + + for event in self.events.itervalues(): + href = "%s_Event_%s.html" % (self.ident, event.ident) + ref = self.frameRef(href, "Status", href, "1", event.short) + code('') + code(''' + +
$ref
$ref ') + for action in trans.actions: + href = "%s_action_%s.html" % (self.ident, action.ident) + ref = self.frameRef(href, "Status", href, "1", + action.short) + code(' $ref\n') + if next != state: + if trans.actions: + code('/') + click = "%s_table_%s.html" % (self.ident, next.ident) + over = "%s_State_%s.html" % (self.ident, next.ident) + ref = self.frameRef(click, "Table", over, "1", next.short) + code("$ref") + code("$ref
$ref
+ + ''') + + + if active_state: + name = "%s_table_%s.html" % (self.ident, active_state.ident) + else: + name = "%s_table.html" % self.ident + code.write(path, name) + + __all__ = [ "StateMachine" ] diff --cc src/mem/slicc/symbols/Type.py index 000000000,2541296dc..bafc6ea9e mode 000000,100644..100644 --- a/src/mem/slicc/symbols/Type.py +++ b/src/mem/slicc/symbols/Type.py @@@ -1,0 -1,650 +1,652 @@@ + # Copyright (c) 1999-2008 Mark D. Hill and David A. Wood + # Copyright (c) 2009 The Hewlett-Packard Development Company + # 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. + + from m5.util import code_formatter, orderdict + + from slicc.util import PairContainer + from slicc.symbols.Symbol import Symbol + + class DataMember(PairContainer): + def __init__(self, ident, type, pairs, init_code): + super(DataMember, self).__init__(pairs) + self.ident = ident + self.type = type + self.init_code = init_code + + class Enumeration(PairContainer): + def __init__(self, ident, pairs): + super(Enumeration, self).__init__(pairs) + self.ident = ident + + class Method(object): + def __init__(self, return_type, param_types): + self.return_type = return_type + self.param_types = param_types + + class Type(Symbol): + def __init__(self, table, ident, location, pairs, machine=None): + super(Type, self).__init__(table, ident, location, pairs) + self.c_ident = ident + if machine: + if self.isExternal or self.isPrimitive: + if "external_name" in self: + self.c_ident = self["external_name"] + else: + # Append with machine name + self.c_ident = "%s_%s" % (machine, ident) + + self.pairs.setdefault("desc", "No description avaliable") + + # check for interface that this Type implements + if "interface" in self: + interface = self["interface"] + if interface in ("Message", "NetworkMessage"): + self["message"] = "yes" + if interface == "NetworkMessage": + self["networkmessage"] = "yes" + + # FIXME - all of the following id comparisons are fragile hacks + if self.ident in ("CacheMemory", "NewCacheMemory", + "TLCCacheMemory", "DNUCACacheMemory", + "DNUCABankCacheMemory", "L2BankCacheMemory", + "CompressedCacheMemory", "PrefetchCacheMemory"): + self["cache"] = "yes" + + if self.ident in ("TBETable", "DNUCATBETable", "DNUCAStopTable"): + self["tbe"] = "yes" + + if self.ident == "NewTBETable": + self["newtbe"] = "yes" + + if self.ident == "TimerTable": + self["timer"] = "yes" + + if self.ident == "DirectoryMemory": + self["dir"] = "yes" + + if self.ident == "PersistentTable": + self["persistent"] = "yes" + + if self.ident == "Prefetcher": + self["prefetcher"] = "yes" + + if self.ident == "DNUCA_Movement": + self["mover"] = "yes" + + self.isMachineType = (ident == "MachineType") + + self.data_members = orderdict() + + # Methods + self.methods = {} + + # Enums + self.enums = orderdict() + + @property + def isPrimitive(self): + return "primitive" in self + @property + def isNetworkMessage(self): + return "networkmessage" in self + @property + def isMessage(self): + return "message" in self + @property + def isBuffer(self): + return "buffer" in self + @property + def isInPort(self): + return "inport" in self + @property + def isOutPort(self): + return "outport" in self + @property + def isEnumeration(self): + return "enumeration" in self + @property + def isExternal(self): + return "external" in self + @property + def isGlobal(self): + return "global" in self + @property + def isInterface(self): + return "interface" in self + + # Return false on error + def dataMemberAdd(self, ident, type, pairs, init_code): + if ident in self.data_members: + return False + + member = DataMember(ident, type, pairs, init_code) + self.data_members[ident] = member + + return True + + def dataMemberType(self, ident): + return self.data_members[ident].type + + def methodId(self, name, param_type_vec): + return '_'.join([name] + [ pt.c_ident for pt in param_type_vec ]) + + def methodAdd(self, name, return_type, param_type_vec): + ident = self.methodId(name, param_type_vec) + if ident in self.methods: + return False + + self.methods[ident] = Method(return_type, param_type_vec) + return True + + def enumAdd(self, ident, pairs): + if ident in self.enums: + return False + + self.enums[ident] = Enumeration(ident, pairs) + + # Add default + if "default" not in self: + self["default"] = "%s_NUM" % self.c_ident + + return True + + def writeCodeFiles(self, path): + if self.isExternal: + # Do nothing + pass + elif self.isEnumeration: + self.printEnumHH(path) + self.printEnumCC(path) + else: + # User defined structs and messages + self.printTypeHH(path) + self.printTypeCC(path) + + def printTypeHH(self, path): + code = code_formatter() + code(''' + /** \\file ${{self.c_ident}}.hh + * + * + * Auto generated C++ code started by $__file__:$__line__ + */ + + #ifndef ${{self.c_ident}}_H + #define ${{self.c_ident}}_H + + #include "mem/ruby/common/Global.hh" + #include "mem/gems_common/Allocator.hh" + ''') + + for dm in self.data_members.values(): + if not dm.type.isPrimitive: + code('#include "mem/protocol/$0.hh"', dm.type.c_ident) + + parent = "" + if "interface" in self: + code('#include "mem/protocol/$0.hh"', self["interface"]) + parent = " : public %s" % self["interface"] + + code(''' + $klass ${{self.c_ident}}$parent { + public: + ${{self.c_ident}}() + ''', klass="class") + + # Call superclass constructor + if "interface" in self: + code(' : ${{self["interface"]}}()') + + code.indent() + code("{") + if not self.isGlobal: + code.indent() + for dm in self.data_members.values(): + ident = dm.ident + if "default" in dm: + # look for default value + code('m_$ident = ${{dm["default"]}}; // default for this field') + elif "default" in dm.type: + # Look for the type default + tid = dm.type.c_ident + code('m_$ident = ${{dm.type["default"]}}; // default value of $tid') + else: + code('// m_$ident has no default') + code.dedent() + code('}') + + # ******** Default destructor ******** + code('~${{self.c_ident}}() { };') + + # ******** Full init constructor ******** + if not self.isGlobal: + params = [ 'const %s& local_%s' % (dm.type.c_ident, dm.ident) \ + for dm in self.data_members.itervalues() ] + + if self.isMessage: + params.append('const unsigned local_proc_id') + + params = ', '.join(params) + code('${{self.c_ident}}($params)') + + # Call superclass constructor + if "interface" in self: + code(' : ${{self["interface"]}}()') + + code('{') + code.indent() + for dm in self.data_members.values(): + code('m_${{dm.ident}} = local_${{dm.ident}};') + if "nextLineCallHack" in dm: + code('m_${{dm.ident}}${{dm["nextLineCallHack"]}};') + + if self.isMessage: + code('proc_id = local_proc_id;') + + code.dedent() + code('}') + + # create a static factory method + if "interface" in self: + code(''' + static ${{self["interface"]}}* create() { + return new ${{self.c_ident}}(); + } + ''') + + # ******** Message member functions ******** + # FIXME: those should be moved into slicc file, slicc should + # support more of the c++ class inheritance + + if self.isMessage: + code(''' + Message* clone() const { checkAllocator(); return s_allocator_ptr->allocate(*this); } + void destroy() { checkAllocator(); s_allocator_ptr->deallocate(this); } + static Allocator<${{self.c_ident}}>* s_allocator_ptr; + static void checkAllocator() { if (s_allocator_ptr == NULL) { s_allocator_ptr = new Allocator<${{self.c_ident}}>; }} + ''') + + if not self.isGlobal: + # const Get methods for each field + code('// Const accessors methods for each field') + for dm in self.data_members.values(): + code(''' + /** \\brief Const accessor method for ${{dm.ident}} field. + * \\return ${{dm.ident}} field + */ + const ${{dm.type.c_ident}}& get${{dm.ident}}() const { return m_${{dm.ident}}; } + ''') + + # Non-const Get methods for each field + code('// Non const Accessors methods for each field') + for dm in self.data_members.values(): + code(''' + /** \\brief Non-const accessor method for ${{dm.ident}} field. + * \\return ${{dm.ident}} field + */ + ${{dm.type.c_ident}}& get${{dm.ident}}() { return m_${{dm.ident}}; } + ''') + + #Set methods for each field + code('// Mutator methods for each field') + for dm in self.data_members.values(): + code(''' + /** \\brief Mutator method for ${{dm.ident}} field */ + void set${{dm.ident}}(const ${{dm.type.c_ident}}& local_${{dm.ident}}) { m_${{dm.ident}} = local_${{dm.ident}}; } + ''') + + code('void print(ostream& out) const;') + code.dedent() + code(' //private:') + code.indent() + + # Data members for each field + for dm in self.data_members.values(): + if "abstract" not in dm: + const = "" + init = "" + + # global structure + if self.isGlobal: + const = "static const " + + # init value + if dm.init_code: + # only global structure can have init value here + assert self.isGlobal + init = " = %s" % (dm.init_code) + + desc = "" + if "desc" in dm: + desc = '/**< %s */' % dm["desc"] + + code('$const${{dm.type.c_ident}} m_${{dm.ident}}$init; $desc') + + if self.isMessage: + code('unsigned proc_id;') + + code.dedent() + code('};') + + code(''' + // Output operator declaration + ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj); + + // Output operator definition + extern inline + ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj) + { + obj.print(out); + out << flush; + return out; + } + + #endif // ${{self.c_ident}}_H + ''') + + code.write(path, "%s.hh" % self.c_ident) + + def printTypeCC(self, path): + code = code_formatter() + + code(''' + /** \\file ${{self.c_ident}}.cc + * + * Auto generated C++ code started by $__file__:$__line__ + */ + + #include "mem/protocol/${{self.c_ident}}.hh" + ''') + + if self.isMessage: + code('Allocator<${{self.c_ident}}>* ${{self.c_ident}}::s_allocator_ptr = NULL;') + code(''' + /** \\brief Print the state of this object */ + void ${{self.c_ident}}::print(ostream& out) const + { + out << "[${{self.c_ident}}: "; + ''') + + # For each field + code.indent() + for dm in self.data_members.values(): + code('out << "${{dm.ident}} = " << m_${{dm.ident}} << " ";''') + + if self.isMessage: + code('out << "Time = " << getTime() << " ";') + code.dedent() + + # Trailer + code(''' + out << "]"; + }''') + + code.write(path, "%s.cc" % self.c_ident) + + def printEnumHH(self, path): + code = code_formatter() + code(''' + /** \\file ${{self.c_ident}}.hh + * + * Auto generated C++ code started by $__file__:$__line__ + */ + #ifndef ${{self.c_ident}}_H + #define ${{self.c_ident}}_H + + #include "mem/ruby/common/Global.hh" + + /** \\enum ${{self.c_ident}} + * \\brief ${{self.desc}} + */ + enum ${{self.c_ident}} { + ${{self.c_ident}}_FIRST, + ''') + + code.indent() + # For each field + for i,(ident,enum) in enumerate(self.enums.iteritems()): + desc = enum.get("desc", "No description avaliable") - init = ' = %s_FIRST' % self.c_ident if i == 0 else '' - ++ if i == 0: ++ init = ' = %s_FIRST' % self.c_ident ++ else: ++ init = '' + code('${{self.c_ident}}_${{enum.ident}}$init, /**< $desc */') + code.dedent() + code(''' + ${{self.c_ident}}_NUM + }; + ${{self.c_ident}} string_to_${{self.c_ident}}(const string& str); + string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj); + ${{self.c_ident}} &operator++(${{self.c_ident}} &e); + ''') + + # MachineType hack used to set the base component id for each Machine + if self.isMachineType: + code(''' + int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj); + MachineType ${{self.c_ident}}_from_base_level(int); + int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj); + int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj); + ''') + + for enum in self.enums.itervalues(): + code('#define MACHINETYPE_${{enum.ident}} 1') + + # Trailer + code(''' + ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj); + + #endif // ${{self.c_ident}}_H + ''') + + code.write(path, "%s.hh" % self.c_ident) + + def printEnumCC(self, path): + code = code_formatter() + code(''' + /** \\file ${{self.c_ident}}.hh + * + * Auto generated C++ code started by $__file__:$__line__ + */ + + #include "mem/protocol/${{self.c_ident}}.hh" + + ''') + + if self.isMachineType: + code('#include "mem/protocol/ControllerFactory.hh"') + for enum in self.enums.itervalues(): + code('#include "mem/protocol/${{enum.ident}}_Controller.hh"') + + code(''' + ostream& operator<<(ostream& out, const ${{self.c_ident}}& obj) + { + out << ${{self.c_ident}}_to_string(obj); + out << flush; + return out; + } + + string ${{self.c_ident}}_to_string(const ${{self.c_ident}}& obj) + { + switch(obj) { + ''') + + # For each field + code.indent() + for enum in self.enums.itervalues(): + code(' case ${{self.c_ident}}_${{enum.ident}}:') + code(' return "${{enum.ident}}";') + code.dedent() + + # Trailer + code(''' + default: + ERROR_MSG("Invalid range for type ${{self.c_ident}}"); + return ""; + } + } + + ${{self.c_ident}} string_to_${{self.c_ident}}(const string& str) + { + ''') + + # For each field + code.indent() + code("if (false) {") + start = "} else " + for enum in self.enums.itervalues(): + code('${start}if (str == "${{enum.ident}}") {') + code(' return ${{self.c_ident}}_${{enum.ident}};') + code.dedent() + + code(''' + } else { + WARN_EXPR(str); + ERROR_MSG("Invalid string conversion for type ${{self.c_ident}}"); + } + } + + ${{self.c_ident}}& operator++(${{self.c_ident}}& e) { + assert(e < ${{self.c_ident}}_NUM); + return e = ${{self.c_ident}}(e+1); + } + ''') + + # MachineType hack used to set the base level and number of + # components for each Machine + if self.isMachineType: + code(''' + /** \\brief returns the base vector index for each machine type to be used by NetDest + * + * \\return the base vector index for each machine type to be used by NetDest + * \\see NetDest.hh + */ + int ${{self.c_ident}}_base_level(const ${{self.c_ident}}& obj) + { + switch(obj) { + ''') + + # For each field + code.indent() + for i,enum in enumerate(self.enums.itervalues()): + code(' case ${{self.c_ident}}_${{enum.ident}}:') + code(' return $i;') + code.dedent() + + # total num + code(''' + case ${{self.c_ident}}_NUM: + return ${{len(self.enums)}}; + + default: + ERROR_MSG("Invalid range for type ${{self.c_ident}}"); + return -1; + } + } + + /** \\brief returns the machine type for each base vector index used by NetDest + * + * \\return the MachineTYpe + */ + MachineType ${{self.c_ident}}_from_base_level(int type) + { + switch(type) { + ''') + + # For each field + code.indent() + for i,enum in enumerate(self.enums.itervalues()): + code(' case $i:') + code(' return ${{self.c_ident}}_${{enum.ident}};') + code.dedent() + + # Trailer + code(''' + default: + ERROR_MSG("Invalid range for type ${{self.c_ident}}"); + return MachineType_NUM; + } + } + + /** \\brief The return value indicates the number of components created + * before a particular machine\'s components + * + * \\return the base number of components for each machine + */ + int ${{self.c_ident}}_base_number(const ${{self.c_ident}}& obj) + { + int base = 0; + switch(obj) { + ''') + + # For each field + code.indent() + code(' case ${{self.c_ident}}_NUM:') + for enum in reversed(self.enums.values()): + code(' base += ${{enum.ident}}_Controller::getNumControllers();') + code(' case ${{self.c_ident}}_${{enum.ident}}:') + code(' break;') + code.dedent() + + code(''' + default: + ERROR_MSG("Invalid range for type ${{self.c_ident}}"); + return -1; + } + + return base; + } + + /** \\brief returns the total number of components for each machine + * \\return the total number of components for each machine + */ + int ${{self.c_ident}}_base_count(const ${{self.c_ident}}& obj) + { + switch(obj) { + ''') + + # For each field + for enum in self.enums.itervalues(): + code(''' + case ${{self.c_ident}}_${{enum.ident}}: + return ${{enum.ident}}_Controller::getNumControllers(); + ''') + + # total num + code(''' + case ${{self.c_ident}}_NUM: + default: + ERROR_MSG("Invalid range for type ${{self.c_ident}}"); + return -1; + } + } + ''') + + # Write the file + code.write(path, "%s.cc" % self.c_ident) + + __all__ = [ "Type" ] diff --cc tests/configs/ruby_config.py index 7b8e27613,fec7bd36c..190337e67 --- a/tests/configs/ruby_config.py +++ b/tests/configs/ruby_config.py @@@ -4,13 -4,17 +4,18 @@@ import subproces from os.path import dirname, join as joinpath import m5 + from m5.params import * - def generate(config_file, cores=1, memories=1, memory_size=1024): + def generate(config_file, cores=1, memories=1, memory_size=1024, \ + cache_size=32768, cache_assoc=8, dmas=1, - ruby_tick='1t', ports_per_cpu=2): ++ ruby_tick='1t', ports_per_cpu=2, protocol='MOESI_CMP_directory'): default = joinpath(dirname(__file__), '../../src/mem/ruby/config') ruby_config = os.environ.get('RUBY_CONFIG', default) args = [ "ruby", "-I", ruby_config, joinpath(ruby_config, "print_cfg.rb"), ++ "-c", str(protocol), "-r", joinpath(ruby_config, config_file), "-p", str(cores), - "-m", str(memories), "-s", str(memory_size)] + "-m", str(memories), "-s", str(memory_size), "-C", str(cache_size), + "-A", str(cache_assoc), "-D", str(dmas)] temp_config = joinpath(m5.options.outdir, "ruby.config") ret = subprocess.call(args, stdout=file(temp_config, "w"))