// 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);
'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)
memory_size_mb = 1024
num_dma = 1
-protocol = "MOESI_CMP_token"
+#default protocol
- protocol = ""#"MESI_CMP_directory"
++protocol = "MOESI_CMP_directory"
# check for overrides
--- /dev/null
- assert(cache_size != -1);
-
- m_cache_num_sets = (cache_size / m_cache_assoc) / RubySystem::getBlockSizeBytes();
- assert(m_cache_num_sets > 1);
+ /*
+ * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ #include "mem/ruby/system/CacheMemory.hh"
+
+ int CacheMemory::m_num_last_level_caches = 0;
+ MachineType CacheMemory::m_last_level_machine_type = MachineType_FIRST;
+
+ // Output operator declaration
+ //ostream& operator<<(ostream& out, const CacheMemory<ENTRY>& obj);
+
+ // ******************* Definitions *******************
+
+ // Output operator definition
+ ostream& operator<<(ostream& out, const CacheMemory& obj)
+ {
+ obj.print(out);
+ out << flush;
+ return out;
+ }
+
+
+ // ****************************************************************
+
+ CacheMemory::CacheMemory(const string & name)
+ : m_cache_name(name)
+ {
+ m_profiler_ptr = new CacheProfiler(name);
+ }
+
+ void CacheMemory::init(const vector<string> & argv)
+ {
+ int cache_size = -1;
+ string policy;
+
+ m_num_last_level_caches =
+ MachineType_base_count(MachineType_FIRST);
+ m_controller = NULL;
+ for (uint32 i=0; i<argv.size(); i+=2) {
+ if (argv[i] == "size") {
+ cache_size = atoi(argv[i+1].c_str());
+ } else if (argv[i] == "latency") {
+ m_latency = atoi(argv[i+1].c_str());
+ } else if (argv[i] == "assoc") {
+ m_cache_assoc = atoi(argv[i+1].c_str());
+ } else if (argv[i] == "replacement_policy") {
+ policy = argv[i+1];
+ } else if (argv[i] == "controller") {
+ m_controller = RubySystem::getController(argv[i+1]);
+ if (m_last_level_machine_type < m_controller->getMachineType()) {
+ m_num_last_level_caches =
+ MachineType_base_count(m_controller->getMachineType());
+ m_last_level_machine_type =
+ m_controller->getMachineType();
+ }
+ } else {
+ cerr << "WARNING: CacheMemory: Unknown configuration parameter: " << argv[i] << endl;
+ }
+ }
+
-CacheMemory::numberOfLastLevelCaches()
++ 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
- 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;
- }
- }
++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)
- return i;
- }
++ m5::hash_map<Address, int>::const_iterator it = m_tag_index.find(tag);
++ if (it != m_tag_index.end())
++ if (m_cache[cacheSet][it->second]->m_Permission != AccessPermission_NotPresent)
++ return it->second;
+ return -1; // Not found
+ }
+
+ // Given a cache index: returns the index of the tag in a set.
+ // returns -1 if the tag is not found.
+ int CacheMemory::findTagInSetIgnorePermissions(Index cacheSet, const Address& tag) const
+ {
+ assert(tag == line_address(tag));
+ // search the set for the tags
++ m5::hash_map<Address, int>::const_iterator it = m_tag_index.find(tag);
++ if (it != m_tag_index.end())
++ return it->second;
+ return -1; // Not found
+ }
+
+ // PUBLIC METHODS
+ bool CacheMemory::tryCacheAccess(const Address& address,
+ CacheRequestType type,
+ DataBlock*& data_ptr)
+ {
+ assert(address == line_address(address));
+ DEBUG_EXPR(CACHE_COMP, HighPrio, address);
+ Index cacheSet = addressToCacheSet(address);
+ int loc = findTagInSet(cacheSet, address);
+ if(loc != -1){ // Do we even have a tag match?
+ AbstractCacheEntry* entry = m_cache[cacheSet][loc];
+ m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime());
+ data_ptr = &(entry->getDataBlk());
+
+ if(entry->m_Permission == AccessPermission_Read_Write) {
+ return true;
+ }
+ if ((entry->m_Permission == AccessPermission_Read_Only) &&
+ (type == CacheRequestType_LD || type == CacheRequestType_IFETCH)) {
+ return true;
+ }
+ // The line must not be accessible
+ }
+ data_ptr = NULL;
+ return false;
+ }
+
+ bool CacheMemory::testCacheAccess(const Address& address,
+ CacheRequestType type,
+ DataBlock*& data_ptr)
+ {
+ assert(address == line_address(address));
+ DEBUG_EXPR(CACHE_COMP, HighPrio, address);
+ Index cacheSet = addressToCacheSet(address);
+ int loc = findTagInSet(cacheSet, address);
+ if(loc != -1){ // Do we even have a tag match?
+ AbstractCacheEntry* entry = m_cache[cacheSet][loc];
+ m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime());
+ data_ptr = &(entry->getDataBlk());
+
+ return (m_cache[cacheSet][loc]->m_Permission != AccessPermission_NotPresent);
+ }
+ data_ptr = NULL;
+ return false;
+ }
+
+ // tests to see if an address is present in the cache
+ bool CacheMemory::isTagPresent(const Address& address) const
+ {
+ assert(address == line_address(address));
+ Index cacheSet = addressToCacheSet(address);
+ int location = findTagInSet(cacheSet, address);
+
+ if (location == -1) {
+ // We didn't find the tag
+ DEBUG_EXPR(CACHE_COMP, LowPrio, address);
+ DEBUG_MSG(CACHE_COMP, LowPrio, "No tag match");
+ return false;
+ }
+ DEBUG_EXPR(CACHE_COMP, LowPrio, address);
+ DEBUG_MSG(CACHE_COMP, LowPrio, "found");
+ return true;
+ }
+
+ // Returns true if there is:
+ // a) a tag match on this address or there is
+ // b) an unused line in the same cache "way"
+ bool CacheMemory::cacheAvail(const Address& address) const
+ {
+ assert(address == line_address(address));
+
+ Index cacheSet = addressToCacheSet(address);
+
+ for (int i=0; i < m_cache_assoc; i++) {
+ AbstractCacheEntry* entry = m_cache[cacheSet][i];
+ if (entry != NULL) {
+ if (entry->m_Address == address || // Already in the cache
+ entry->m_Permission == AccessPermission_NotPresent) { // We found an empty entry
+ return true;
+ }
+ } else {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry)
+ {
+ assert(address == line_address(address));
+ assert(!isTagPresent(address));
+ assert(cacheAvail(address));
+ DEBUG_EXPR(CACHE_COMP, HighPrio, address);
+
+ // Find the first open slot
+ Index cacheSet = addressToCacheSet(address);
+ for (int i=0; i < m_cache_assoc; i++) {
+ if (m_cache[cacheSet][i] == NULL ||
+ m_cache[cacheSet][i]->m_Permission == AccessPermission_NotPresent) {
+ m_cache[cacheSet][i] = entry; // Init entry
+ m_cache[cacheSet][i]->m_Address = address;
+ m_cache[cacheSet][i]->m_Permission = AccessPermission_Invalid;
+ m_locked[cacheSet][i] = -1;
++ m_tag_index[address] = i;
+
+ m_replacementPolicy_ptr->touch(cacheSet, i, g_eventQueue_ptr->getTime());
+
+ return;
+ }
+ }
+ ERROR_MSG("Allocate didn't find an available entry");
+ }
+
+ void CacheMemory::deallocate(const Address& address)
+ {
+ assert(address == line_address(address));
+ assert(isTagPresent(address));
+ DEBUG_EXPR(CACHE_COMP, HighPrio, address);
+ Index cacheSet = addressToCacheSet(address);
+ int location = findTagInSet(cacheSet, address);
+ if (location != -1){
+ delete m_cache[cacheSet][location];
+ m_cache[cacheSet][location] = NULL;
+ m_locked[cacheSet][location] = -1;
++ m_tag_index.erase(address);
+ }
+ }
+
+ // Returns with the physical address of the conflicting cache line
+ Address CacheMemory::cacheProbe(const Address& address) const
+ {
+ assert(address == line_address(address));
+ assert(!cacheAvail(address));
+
+ Index cacheSet = addressToCacheSet(address);
+ return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)]->m_Address;
+ }
+
+ // looks an address up in the cache
+ AbstractCacheEntry& CacheMemory::lookup(const Address& address)
+ {
+ assert(address == line_address(address));
+ Index cacheSet = addressToCacheSet(address);
+ int loc = findTagInSet(cacheSet, address);
+ assert(loc != -1);
+ return *m_cache[cacheSet][loc];
+ }
+
+ // looks an address up in the cache
+ const AbstractCacheEntry& CacheMemory::lookup(const Address& address) const
+ {
+ assert(address == line_address(address));
+ Index cacheSet = addressToCacheSet(address);
+ int loc = findTagInSet(cacheSet, address);
+ assert(loc != -1);
+ return *m_cache[cacheSet][loc];
+ }
+
+ AccessPermission CacheMemory::getPermission(const Address& address) const
+ {
+ assert(address == line_address(address));
+ return lookup(address).m_Permission;
+ }
+
+ void CacheMemory::changePermission(const Address& address, AccessPermission new_perm)
+ {
+ assert(address == line_address(address));
+ lookup(address).m_Permission = new_perm;
+ Index cacheSet = addressToCacheSet(address);
+ int loc = findTagInSet(cacheSet, address);
+ m_locked[cacheSet][loc] = -1;
+ assert(getPermission(address) == new_perm);
+ }
+
+ // Sets the most recently used bit for a cache block
+ void CacheMemory::setMRU(const Address& address)
+ {
+ Index cacheSet;
+
+ cacheSet = addressToCacheSet(address);
+ m_replacementPolicy_ptr->touch(cacheSet,
+ findTagInSet(cacheSet, address),
+ g_eventQueue_ptr->getTime());
+ }
+
+ void CacheMemory::profileMiss(const CacheMsg & msg)
+ {
+ m_profiler_ptr->addStatSample(msg.getType(), msg.getAccessMode(),
+ msg.getSize(), msg.getPrefetch());
+ }
+
+ void CacheMemory::recordCacheContents(CacheRecorder& tr) const
+ {
+ for (int i = 0; i < m_cache_num_sets; i++) {
+ for (int j = 0; j < m_cache_assoc; j++) {
+ AccessPermission perm = m_cache[i][j]->m_Permission;
+ CacheRequestType request_type = CacheRequestType_NULL;
+ if (perm == AccessPermission_Read_Only) {
+ if (m_is_instruction_only_cache) {
+ request_type = CacheRequestType_IFETCH;
+ } else {
+ request_type = CacheRequestType_LD;
+ }
+ } else if (perm == AccessPermission_Read_Write) {
+ request_type = CacheRequestType_ST;
+ }
+
+ if (request_type != CacheRequestType_NULL) {
+ // tr.addRecord(m_chip_ptr->getID(), m_cache[i][j].m_Address,
+ // Address(0), request_type, m_replacementPolicy_ptr->getLastAccess(i, j));
+ }
+ }
+ }
+ }
+
+ void CacheMemory::print(ostream& out) const
+ {
+ out << "Cache dump: " << m_cache_name << endl;
+ for (int i = 0; i < m_cache_num_sets; i++) {
+ for (int j = 0; j < m_cache_assoc; j++) {
+ if (m_cache[i][j] != NULL) {
+ out << " Index: " << i
+ << " way: " << j
+ << " entry: " << *m_cache[i][j] << endl;
+ } else {
+ out << " Index: " << i
+ << " way: " << j
+ << " entry: NULL" << endl;
+ }
+ }
+ }
+ }
+
+ void CacheMemory::printData(ostream& out) const
+ {
+ out << "printData() not supported" << endl;
+ }
+
+ void CacheMemory::clearStats() const
+ {
+ m_profiler_ptr->clearStats();
+ }
+
+ void CacheMemory::printStats(ostream& out) const
+ {
+ m_profiler_ptr->printStats(out);
+ }
+
+ void CacheMemory::getMemoryValue(const Address& addr, char* value,
+ unsigned int size_in_bytes ){
+ AbstractCacheEntry& entry = lookup(line_address(addr));
+ unsigned int startByte = addr.getAddress() - line_address(addr).getAddress();
+ for(unsigned int i=0; i<size_in_bytes; ++i){
+ value[i] = entry.getDataBlk().getByte(i + startByte);
+ }
+ }
+
+ void CacheMemory::setMemoryValue(const Address& addr, char* value,
+ unsigned int size_in_bytes ){
+ AbstractCacheEntry& entry = lookup(line_address(addr));
+ unsigned int startByte = addr.getAddress() - line_address(addr).getAddress();
+ assert(size_in_bytes > 0);
+ for(unsigned int i=0; i<size_in_bytes; ++i){
+ entry.getDataBlk().setByte(i + startByte, value[i]);
+ }
+
+ // entry = lookup(line_address(addr));
+ }
+
+ void
+ CacheMemory::setLocked(const Address& address, int context)
+ {
+ assert(address == line_address(address));
+ Index cacheSet = addressToCacheSet(address);
+ int loc = findTagInSet(cacheSet, address);
+ assert(loc != -1);
+ m_locked[cacheSet][loc] = context;
+ }
+
+ void
+ CacheMemory::clearLocked(const Address& address)
+ {
+ assert(address == line_address(address));
+ Index cacheSet = addressToCacheSet(address);
+ int loc = findTagInSet(cacheSet, address);
+ assert(loc != -1);
+ m_locked[cacheSet][loc] = -1;
+ }
+
+ bool
+ CacheMemory::isLocked(const Address& address, int context)
+ {
+ assert(address == line_address(address));
+ Index cacheSet = addressToCacheSet(address);
+ int loc = findTagInSet(cacheSet, address);
+ assert(loc != -1);
+ return m_locked[cacheSet][loc] == context;
+ }
+
#include "mem/ruby/slicc_interface/AbstractController.hh"
#include "mem/ruby/profiler/CacheProfiler.hh"
#include "mem/protocol/CacheMsg.hh"
++#include "base/hashmap.hh"
#include <vector>
class CacheMemory {
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
int m_cache_num_set_bits;
int m_cache_assoc;
- };
+ static Vector< CacheMemory* > m_all_caches;
- static Vector< CacheMemory* > m_all_caches;
++
+ static int m_num_last_level_caches;
+ static MachineType m_last_level_machine_type;
- // Output operator declaration
- //ostream& operator<<(ostream& out, const CacheMemory<ENTRY>& obj);
-
- // ******************* Definitions *******************
-
- // Output operator definition
- inline
- ostream& operator<<(ostream& out, const CacheMemory& obj)
- {
- obj.print(out);
- out << flush;
- return out;
- }
-
-
- // ****************************************************************
-
- inline
- CacheMemory::CacheMemory(const string & name)
- : m_cache_name(name)
- {
- m_profiler_ptr = new CacheProfiler(name);
- }
-
- inline
- void CacheMemory::init(const vector<string> & argv)
- {
- int cache_size = 0;
- string policy;
-
- m_controller = NULL;
- for (uint32 i=0; i<argv.size(); i+=2) {
- if (argv[i] == "size_kb") {
- cache_size = atoi(argv[i+1].c_str());
- } else if (argv[i] == "latency") {
- m_latency = atoi(argv[i+1].c_str());
- } else if (argv[i] == "assoc") {
- m_cache_assoc = atoi(argv[i+1].c_str());
- } else if (argv[i] == "replacement_policy") {
- policy = argv[i+1];
- } else if (argv[i] == "controller") {
- m_controller = RubySystem::getController(argv[i+1]);
- } else {
- cerr << "WARNING: CacheMemory: Unknown configuration parameter: " << argv[i] << endl;
- }
- }
-
- int num_lines = (cache_size*1024)/RubySystem::getBlockSizeBytes();
- m_cache_num_sets = num_lines / m_cache_assoc;
- m_cache_num_set_bits = log_int(m_cache_num_sets);
-
- if(policy == "PSEUDO_LRU")
- m_replacementPolicy_ptr = new PseudoLRUPolicy(m_cache_num_sets, m_cache_assoc);
- else if (policy == "LRU")
- m_replacementPolicy_ptr = new LRUPolicy(m_cache_num_sets, m_cache_assoc);
- else
- assert(false);
-
- m_cache.setSize(m_cache_num_sets);
- m_locked.setSize(m_cache_num_sets);
- for (int i = 0; i < m_cache_num_sets; i++) {
- m_cache[i].setSize(m_cache_assoc);
- m_locked[i].setSize(m_cache_assoc);
- for (int j = 0; j < m_cache_assoc; j++) {
- m_cache[i][j] = NULL;
- m_locked[i][j] = -1;
- }
- }
- }
-
- inline
- CacheMemory::~CacheMemory()
- {
- if(m_replacementPolicy_ptr != NULL)
- delete m_replacementPolicy_ptr;
- }
-
- inline
- void CacheMemory::printConfig(ostream& out)
- {
- out << "Cache config: " << m_cache_name << endl;
- if (m_controller != NULL)
- out << " controller: " << m_controller->getName() << endl;
- out << " cache_associativity: " << m_cache_assoc << endl;
- out << " num_cache_sets_bits: " << m_cache_num_set_bits << endl;
- const int cache_num_sets = 1 << m_cache_num_set_bits;
- out << " num_cache_sets: " << cache_num_sets << endl;
- out << " cache_set_size_bytes: " << cache_num_sets * RubySystem::getBlockSizeBytes() << endl;
- out << " cache_set_size_Kbytes: "
- << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<10) << endl;
- out << " cache_set_size_Mbytes: "
- << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<20) << endl;
- out << " cache_size_bytes: "
- << cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc << endl;
- out << " cache_size_Kbytes: "
- << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<10) << endl;
- out << " cache_size_Mbytes: "
- << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<20) << endl;
- }
-
- // PRIVATE METHODS
-
- // convert a Address to its location in the cache
- inline
- Index CacheMemory::addressToCacheSet(const Address& address) const
- {
- assert(address == line_address(address));
- return address.bitSelect(RubySystem::getBlockSizeBits(), RubySystem::getBlockSizeBits() + m_cache_num_set_bits-1);
- }
-
- // Given a cache index: returns the index of the tag in a set.
- // returns -1 if the tag is not found.
- inline
- int CacheMemory::findTagInSet(Index cacheSet, const Address& tag) const
- {
- assert(tag == line_address(tag));
- // search the set for the tags
- m5::hash_map<Address, int>::const_iterator it = m_tag_index.find(tag);
- if (it != m_tag_index.end())
- if (m_cache[cacheSet][it->second]->m_Permission != AccessPermission_NotPresent)
- return it->second;
- return -1; // Not found
- }
-
- // Given a cache index: returns the index of the tag in a set.
- // returns -1 if the tag is not found.
- inline
- int CacheMemory::findTagInSetIgnorePermissions(Index cacheSet, const Address& tag) const
- {
- assert(tag == line_address(tag));
- // search the set for the tags
- m5::hash_map<Address, int>::const_iterator it = m_tag_index.find(tag);
- if (it != m_tag_index.end())
- return it->second;
- return -1; // Not found
- }
-
- // PUBLIC METHODS
- inline
- bool CacheMemory::tryCacheAccess(const Address& address,
- CacheRequestType type,
- DataBlock*& data_ptr)
- {
- assert(address == line_address(address));
- DEBUG_EXPR(CACHE_COMP, HighPrio, address);
- Index cacheSet = addressToCacheSet(address);
- int loc = findTagInSet(cacheSet, address);
- if(loc != -1){ // Do we even have a tag match?
- AbstractCacheEntry* entry = m_cache[cacheSet][loc];
- m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime());
- data_ptr = &(entry->getDataBlk());
-
- if(entry->m_Permission == AccessPermission_Read_Write) {
- return true;
- }
- if ((entry->m_Permission == AccessPermission_Read_Only) &&
- (type == CacheRequestType_LD || type == CacheRequestType_IFETCH)) {
- return true;
- }
- // The line must not be accessible
- }
- data_ptr = NULL;
- return false;
- }
-
- inline
- bool CacheMemory::testCacheAccess(const Address& address,
- CacheRequestType type,
- DataBlock*& data_ptr)
- {
- assert(address == line_address(address));
- DEBUG_EXPR(CACHE_COMP, HighPrio, address);
- Index cacheSet = addressToCacheSet(address);
- int loc = findTagInSet(cacheSet, address);
- if(loc != -1){ // Do we even have a tag match?
- AbstractCacheEntry* entry = m_cache[cacheSet][loc];
- m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime());
- data_ptr = &(entry->getDataBlk());
-
- return (m_cache[cacheSet][loc]->m_Permission != AccessPermission_NotPresent);
- }
- data_ptr = NULL;
- return false;
- }
-
- // tests to see if an address is present in the cache
- inline
- bool CacheMemory::isTagPresent(const Address& address) const
- {
- assert(address == line_address(address));
- Index cacheSet = addressToCacheSet(address);
- int location = findTagInSet(cacheSet, address);
-
- if (location == -1) {
- // We didn't find the tag
- DEBUG_EXPR(CACHE_COMP, LowPrio, address);
- DEBUG_MSG(CACHE_COMP, LowPrio, "No tag match");
- return false;
- }
- DEBUG_EXPR(CACHE_COMP, LowPrio, address);
- DEBUG_MSG(CACHE_COMP, LowPrio, "found");
- return true;
- }
-
- // Returns true if there is:
- // a) a tag match on this address or there is
- // b) an unused line in the same cache "way"
- inline
- bool CacheMemory::cacheAvail(const Address& address) const
- {
- assert(address == line_address(address));
-
- Index cacheSet = addressToCacheSet(address);
-
- for (int i=0; i < m_cache_assoc; i++) {
- AbstractCacheEntry* entry = m_cache[cacheSet][i];
- if (entry != NULL) {
- if (entry->m_Address == address || // Already in the cache
- entry->m_Permission == AccessPermission_NotPresent) { // We found an empty entry
- return true;
- }
- } else {
- return true;
- }
- }
- return false;
- }
-
- inline
- void CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry)
- {
- assert(address == line_address(address));
- assert(!isTagPresent(address));
- assert(cacheAvail(address));
- DEBUG_EXPR(CACHE_COMP, HighPrio, address);
-
- // Find the first open slot
- Index cacheSet = addressToCacheSet(address);
- for (int i=0; i < m_cache_assoc; i++) {
- if (m_cache[cacheSet][i] == NULL ||
- m_cache[cacheSet][i]->m_Permission == AccessPermission_NotPresent) {
- m_cache[cacheSet][i] = entry; // Init entry
- m_cache[cacheSet][i]->m_Address = address;
- m_cache[cacheSet][i]->m_Permission = AccessPermission_Invalid;
- m_locked[cacheSet][i] = -1;
- m_tag_index[address] = i;
-
- m_replacementPolicy_ptr->touch(cacheSet, i, g_eventQueue_ptr->getTime());
-
- return;
- }
- }
- ERROR_MSG("Allocate didn't find an available entry");
- }
-
- inline
- void CacheMemory::deallocate(const Address& address)
- {
- assert(address == line_address(address));
- assert(isTagPresent(address));
- DEBUG_EXPR(CACHE_COMP, HighPrio, address);
- Index cacheSet = addressToCacheSet(address);
- int location = findTagInSet(cacheSet, address);
- if (location != -1){
- delete m_cache[cacheSet][location];
- m_cache[cacheSet][location] = NULL;
- m_locked[cacheSet][location] = -1;
- m_tag_index.erase(address);
- }
- }
-
- // Returns with the physical address of the conflicting cache line
- inline
- Address CacheMemory::cacheProbe(const Address& address) const
- {
- assert(address == line_address(address));
- assert(!cacheAvail(address));
-
- Index cacheSet = addressToCacheSet(address);
- return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)]->m_Address;
- }
-
- // looks an address up in the cache
- inline
- AbstractCacheEntry& CacheMemory::lookup(const Address& address)
- {
- assert(address == line_address(address));
- Index cacheSet = addressToCacheSet(address);
- int loc = findTagInSet(cacheSet, address);
- assert(loc != -1);
- return *m_cache[cacheSet][loc];
- }
-
- // looks an address up in the cache
- inline
- const AbstractCacheEntry& CacheMemory::lookup(const Address& address) const
- {
- assert(address == line_address(address));
- Index cacheSet = addressToCacheSet(address);
- int loc = findTagInSet(cacheSet, address);
- assert(loc != -1);
- return *m_cache[cacheSet][loc];
- }
-
- inline
- AccessPermission CacheMemory::getPermission(const Address& address) const
- {
- assert(address == line_address(address));
- return lookup(address).m_Permission;
- }
-
- inline
- void CacheMemory::changePermission(const Address& address, AccessPermission new_perm)
- {
- assert(address == line_address(address));
- lookup(address).m_Permission = new_perm;
- Index cacheSet = addressToCacheSet(address);
- int loc = findTagInSet(cacheSet, address);
- m_locked[cacheSet][loc] = -1;
- assert(getPermission(address) == new_perm);
- }
-
- // Sets the most recently used bit for a cache block
- inline
- void CacheMemory::setMRU(const Address& address)
- {
- Index cacheSet;
-
- cacheSet = addressToCacheSet(address);
- m_replacementPolicy_ptr->touch(cacheSet,
- findTagInSet(cacheSet, address),
- g_eventQueue_ptr->getTime());
- }
-
- inline
- void CacheMemory::profileMiss(const CacheMsg & msg)
- {
- m_profiler_ptr->addStatSample(msg.getType(), msg.getAccessMode(),
- msg.getSize(), msg.getPrefetch());
- }
-
- inline
- void CacheMemory::recordCacheContents(CacheRecorder& tr) const
- {
- for (int i = 0; i < m_cache_num_sets; i++) {
- for (int j = 0; j < m_cache_assoc; j++) {
- AccessPermission perm = m_cache[i][j]->m_Permission;
- CacheRequestType request_type = CacheRequestType_NULL;
- if (perm == AccessPermission_Read_Only) {
- if (m_is_instruction_only_cache) {
- request_type = CacheRequestType_IFETCH;
- } else {
- request_type = CacheRequestType_LD;
- }
- } else if (perm == AccessPermission_Read_Write) {
- request_type = CacheRequestType_ST;
- }
-
- if (request_type != CacheRequestType_NULL) {
- // tr.addRecord(m_chip_ptr->getID(), m_cache[i][j].m_Address,
- // Address(0), request_type, m_replacementPolicy_ptr->getLastAccess(i, j));
- }
- }
- }
- }
-
- inline
- void CacheMemory::print(ostream& out) const
- {
- out << "Cache dump: " << m_cache_name << endl;
- for (int i = 0; i < m_cache_num_sets; i++) {
- for (int j = 0; j < m_cache_assoc; j++) {
- if (m_cache[i][j] != NULL) {
- out << " Index: " << i
- << " way: " << j
- << " entry: " << *m_cache[i][j] << endl;
- } else {
- out << " Index: " << i
- << " way: " << j
- << " entry: NULL" << endl;
- }
- }
- }
- }
-
- inline
- void CacheMemory::printData(ostream& out) const
- {
- out << "printData() not supported" << endl;
- }
-
- inline void CacheMemory::clearStats() const
- {
- m_profiler_ptr->clearStats();
- }
-
- inline
- void CacheMemory::printStats(ostream& out) const
- {
- m_profiler_ptr->printStats(out);
- }
-
- inline
- void CacheMemory::getMemoryValue(const Address& addr, char* value,
- unsigned int size_in_bytes ){
- AbstractCacheEntry& entry = lookup(line_address(addr));
- unsigned int startByte = addr.getAddress() - line_address(addr).getAddress();
- for(unsigned int i=0; i<size_in_bytes; ++i){
- value[i] = entry.getDataBlk().getByte(i + startByte);
- }
- }
-
- inline
- void CacheMemory::setMemoryValue(const Address& addr, char* value,
- unsigned int size_in_bytes ){
- AbstractCacheEntry& entry = lookup(line_address(addr));
- unsigned int startByte = addr.getAddress() - line_address(addr).getAddress();
- assert(size_in_bytes > 0);
- for(unsigned int i=0; i<size_in_bytes; ++i){
- entry.getDataBlk().setByte(i + startByte, value[i]);
- }
-
- // entry = lookup(line_address(addr));
- }
-
- inline
- void
- CacheMemory::setLocked(const Address& address, int context)
- {
- assert(address == line_address(address));
- Index cacheSet = addressToCacheSet(address);
- int loc = findTagInSet(cacheSet, address);
- assert(loc != -1);
- m_locked[cacheSet][loc] = context;
- }
-
- inline
- void
- CacheMemory::clearLocked(const Address& address)
- {
- assert(address == line_address(address));
- Index cacheSet = addressToCacheSet(address);
- int loc = findTagInSet(cacheSet, address);
- assert(loc != -1);
- m_locked[cacheSet][loc] = -1;
- }
-
- inline
- bool
- CacheMemory::isLocked(const Address& address, int context)
- {
- assert(address == line_address(address));
- Index cacheSet = addressToCacheSet(address);
- int loc = findTagInSet(cacheSet, address);
- assert(loc != -1);
- return m_locked[cacheSet][loc] == context;
- }
+
+ };
#endif //CACHEMEMORY_H
--- /dev/null
- void started_writes();
- void clear_atomic();
+ # 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.symbols.Symbol import Symbol
+ from slicc.symbols.Var import Var
+ import slicc.generate.html as html
+
+ class StateMachine(Symbol):
+ def __init__(self, symtab, ident, location, pairs, config_parameters):
+ super(StateMachine, self).__init__(symtab, ident, location, pairs)
+ self.table = None
+ self.config_parameters = config_parameters
+ for param in config_parameters:
+ var = Var(symtab, param.name, location, param.type_ast.type,
+ "m_%s" % param.name, {}, self)
+ self.symtab.registerSym(param.name, var)
+
+ self.states = orderdict()
+ self.events = orderdict()
+ self.actions = orderdict()
+ self.transitions = []
+ self.in_ports = []
+ self.functions = []
+ self.objects = []
+
+ self.message_buffer_names = []
+
+ def __repr__(self):
+ return "[StateMachine: %s]" % self.ident
+
+ def addState(self, state):
+ assert self.table is None
+ self.states[state.ident] = state
+
+ def addEvent(self, event):
+ assert self.table is None
+ self.events[event.ident] = event
+
+ def addAction(self, action):
+ assert self.table is None
+
+ # Check for duplicate action
+ for other in self.actions.itervalues():
+ if action.ident == other.ident:
+ action.warning("Duplicate action definition: %s" % action.ident)
+ action.error("Duplicate action definition: %s" % action.ident)
+ if action.short == other.short:
+ other.warning("Duplicate action shorthand: %s" % other.ident)
+ other.warning(" shorthand = %s" % other.short)
+ action.warning("Duplicate action shorthand: %s" % action.ident)
+ action.error(" shorthand = %s" % action.short)
+
+ self.actions[action.ident] = action
+
+ def addTransition(self, trans):
+ assert self.table is None
+ self.transitions.append(trans)
+
+ def addInPort(self, var):
+ self.in_ports.append(var)
+
+ def addFunc(self, func):
+ # register func in the symbol table
+ self.symtab.registerSym(str(func), func)
+ self.functions.append(func)
+
+ def addObject(self, obj):
+ self.objects.append(obj)
+
+ # Needs to be called before accessing the table
+ def buildTable(self):
+ assert self.table is None
+
+ table = {}
+
+ for trans in self.transitions:
+ # Track which actions we touch so we know if we use them
+ # all -- really this should be done for all symbols as
+ # part of the symbol table, then only trigger it for
+ # Actions, States, Events, etc.
+
+ for action in trans.actions:
+ action.used = True
+
+ index = (trans.state, trans.event)
+ if index in table:
+ table[index].warning("Duplicate transition: %s" % table[index])
+ trans.error("Duplicate transition: %s" % trans)
+ table[index] = trans
+
+ # Look at all actions to make sure we used them all
+ for action in self.actions.itervalues():
+ if not action.used:
+ error_msg = "Unused action: %s" % action.ident
+ if "desc" in action:
+ error_msg += ", " + action.desc
+ action.warning(error_msg)
+ self.table = table
+
+ def writeCodeFiles(self, path):
+ self.printControllerHH(path)
+ self.printControllerCC(path)
+ self.printCSwitch(path)
+ self.printCWakeup(path)
+ self.printProfilerCC(path)
+ self.printProfilerHH(path)
+
+ for func in self.functions:
+ func.writeCodeFiles(path)
+
+ def printControllerHH(self, path):
+ '''Output the method declarations for the class declaration'''
+ code = code_formatter()
+ ident = self.ident
+ c_ident = "%s_Controller" % self.ident
+
+ self.message_buffer_names = []
+
+ code('''
+ /** \\file $ident.hh
+ *
+ * Auto generated C++ code started by $__file__:$__line__
+ * Created by slicc definition of Module "${{self.short}}"
+ */
+
+ #ifndef ${ident}_CONTROLLER_H
+ #define ${ident}_CONTROLLER_H
+
+ #include "mem/ruby/common/Global.hh"
+ #include "mem/ruby/common/Consumer.hh"
+ #include "mem/ruby/slicc_interface/AbstractController.hh"
+ #include "mem/protocol/TransitionResult.hh"
+ #include "mem/protocol/Types.hh"
+ #include "mem/protocol/${ident}_Profiler.hh"
+ ''')
+
+ 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)
+
+ # for adding information to the protocol debug trace
+ code('''
+ extern stringstream ${ident}_transitionComment;
+
+ class $c_ident : public AbstractController {
+ #ifdef CHECK_COHERENCE
+ #endif /* CHECK_COHERENCE */
+ public:
+ $c_ident(const string & name);
+ static int getNumControllers();
+ void init(Network* net_ptr, const vector<string> & 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);
-bool started_receiving_writes;
++ 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;
-started_receiving_writes = false;
+ 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;
- 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:]
+ 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<string> &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<string, string>::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"]
+
- if str(port).find("forwardRequestNetwork_in") >= 0:
+ code('$output')
+
+ for port in self.in_ports:
+ # don't print out mandatory queue twice
+ if port == mandatory_q:
+ continue
+
+ if ident == "L1Cache":
- 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 (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<const RequestMsg*>(((*m_L1Cache_forwardToCache_ptr)).peek());
- if str(port).find("forwardRequestNetwork_in") >= 0:
++ 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":
-void ${ident}_Controller::started_writes()
++ 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);
++
++ }
+ }
+
- started_receiving_writes = true;
++void ${ident}_Controller::clear_atomic(Address addr)
+ {
-void ${ident}_Controller::clear_atomic()
++
++ 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--;
++
+ }
+
- 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);
- }
++void ${ident}_Controller::reset_atomics()
+ {
-void ${ident}_Controller::started_writes()
++
++ 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::clear_atomic()
++void ${ident}_Controller::reset_atomics()
+ {
+ assert(0);
+ }
+
+ void ${ident}_Controller::set_atomic(Address addr)
+ {
+ assert(0);
+ }
+
++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("""<A href=\"$click_href\" target=\"$click_target\" onMouseOver=\"if (parent.frames[$over_target_num].location != parent.location + '$over_href') { parent.frames[$over_target_num].location='$over_href' }\" >${{html.formatShorthand(text)}}</A>""")
+ 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><BODY link="blue" vlink="blue">
+
+ <H1 align="center">${{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<A target="Table" href="${mid}_table.html">$mid</A>')
+ code.dedent()
+
+ code("""
+ </H1>
+
+ <TABLE border=1>
+ <TR>
+ <TH> </TH>
+ """)
+
+ 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('<TH bgcolor=white>$ref</TH>')
+
+ code('</TR>')
+ # -- 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('''
+ <TR>
+ <TH bgcolor=$color>$ref</TH>
+ ''')
+
+ # -- 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('<TD bgcolor=$color> </TD>')
+ 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('<TD bgcolor=$color>')
+ 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("</TD>\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('''
+ <TH bgcolor=$color>$ref</TH>
+ </TR>
+ ''')
+ code('''
+ <TR>
+ <TH> </TH>
+ ''')
+
+ 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('<TH bgcolor=white>$ref</TH>')
+ code('''
+ </TR>
+ </TABLE>
+ </BODY></HTML>
+ ''')
+
+
+ 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" ]
--- /dev/null
- init = ' = %s_FIRST' % self.c_ident if i == 0 else ''
-
+ # 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")
++ 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" ]
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"))