merge
authorDerek Hower <drh5@cs.wisc.edu>
Tue, 19 Jan 2010 21:48:12 +0000 (15:48 -0600)
committerDerek Hower <drh5@cs.wisc.edu>
Tue, 19 Jan 2010 21:48:12 +0000 (15:48 -0600)
14 files changed:
1  2 
src/mem/protocol/MI_example-dir.sm
src/mem/protocol/RubySlicc_ComponentMapping.sm
src/mem/protocol/SConsopts
src/mem/ruby/config/MI_example-homogeneous.rb
src/mem/ruby/config/TwoLevel_SplitL1UnifiedL2.rb
src/mem/ruby/libruby.hh
src/mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh
src/mem/ruby/system/CacheMemory.cc
src/mem/ruby/system/CacheMemory.hh
src/mem/ruby/system/DirectoryMemory.cc
src/mem/ruby/system/Sequencer.hh
src/mem/slicc/symbols/StateMachine.py
src/mem/slicc/symbols/Type.py
tests/configs/ruby_config.py

Simple merge
index 0da1a05e2336c7a69f0c04d81fb606a10f218c59,2a027554ed8bdd4686d95933f27260e6600a7026..891820c46fa7d8e584e50f91daccc6beada22b11
  
  // 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);
index ded0814d28e7032e1f791f5cd7d89e5727c1d326,7be9fd97e812eee2d5ac3e0e6ac10db2c13ba7f8..10a303681db069170805873b21029839ee480fda
@@@ -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)
index a4a1982f4b9670836653a13fa61d533f04d9b05a,566055f746d96d3a6cc35acc67c63dd104e48d33..a8ef1eceba3def226a52597372c9c909a0a03c9a
@@@ -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
  
Simple merge
index 0000000000000000000000000000000000000000,630b945427d453b701791d52a91b7d1ef23e2f65..cf3e094ad0e7d0046e4130412cbe8f5cf81620af
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,487 +1,483 @@@
 -  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; 
+ }
index 7268189ea0c0374b675408fe63d1bb47a9c80383,856b7bcac652403be92881024cae8d2b22a27990..8b84f33ecf5cbfc8b777a6f83a88c40410fb966e
@@@ -54,6 -54,6 +54,7 @@@
  #include "mem/ruby/slicc_interface/AbstractController.hh"
  #include "mem/ruby/profiler/CacheProfiler.hh"
  #include "mem/protocol/CacheMsg.hh"
++#include "base/hashmap.hh"
  #include <vector>
  
  class CacheMemory {
@@@ -104,6 -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 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
  
Simple merge
index 0000000000000000000000000000000000000000,0084388698c8ea5d1cec8754b3c04bdaf9045d2f..af9850896c4bc556f5dada18445f867131725668
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1225 +1,1164 @@@
 -    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>&nbsp;</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" ]
index 0000000000000000000000000000000000000000,2541296dcbff7ac22d240aba327356de555685df..bafc6ea9eed891ed9910498d65cee5e24d22c834
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,650 +1,652 @@@
 -            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" ]
index 7b8e2761365773f8f848ca3fc027193f31e90e2a,fec7bd36c26a1b49ccd56f00533ee4ea6e8254d7..190337e6747a8da5f94ee56e58b209da155a710a
@@@ -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"))