# HG changeset patch
# User Brad Beckmann <[email protected]>
# Date 1268941833 25200
# Node ID bd4aafe90771a0ed4936f90994b717cdf4d99957
# Parent  585c0e7c5f4509f845617b1eed9cda77e910c4df
ruby: Ruby support for sparse memory including direct support in the
protocol MI example.

diff --git a/configs/common/Options.py b/configs/common/Options.py
--- a/configs/common/Options.py
+++ b/configs/common/Options.py
@@ -43,7 +43,11 @@
                   help="the number of rows in the mesh topology")
 parser.add_option("--garnet-network", type="string", default=none,
                   help="'fixed'|'flexible'")
-      
+
+# ruby sparse memory options
+parser.add_option("--use-map", action="store_true", default=False)
+parser.add_option("--map-levels", type="int", default=4)
+
 # Run duration options
 parser.add_option("-m", "--maxtick", type="int", default=m5.MaxTick,
                   metavar="T",
diff --git a/configs/ruby/MI_example.py b/configs/ruby/MI_example.py
--- a/configs/ruby/MI_example.py
+++ b/configs/ruby/MI_example.py
@@ -105,7 +105,9 @@
         dir_cntrl = Directory_Controller(version = i,
                                          directory = \
                                          RubyDirectoryMemory(version = i,
-                                                             size = dir_size),
+                                               size = dir_size,
+                                               use_map = options.use_map,
+                                               map_levels = 
options.map_levels),
                                          memBuffer = mem_cntrl)
 
         dir_cntrl_nodes.append(dir_cntrl)
diff --git a/configs/ruby/Ruby.py b/configs/ruby/Ruby.py
--- a/configs/ruby/Ruby.py
+++ b/configs/ruby/Ruby.py
@@ -78,15 +78,17 @@
         network = SimpleNetwork(topology = net_topology)
 
     #
-    # determine the total memory size of the ruby system and verify it is equal
-    # to physmem
+    # Determine the total memory size of the ruby system and verify it is equal
+    # to physmem.  However, if Ruby memory is using sparse memory in SE 
+    # mode, then the system should not back-up the memory state with
+    # the Memory Vector and thus the memory size bytes should stay at 0.
     #
     total_mem_size = MemorySize('0B')
     for dir_cntrl in dir_cntrls:
         total_mem_size.value += dir_cntrl.directory.size.value
     physmem_size = long(physmem.range.second) - long(physmem.range.first) + 1
     assert(total_mem_size.value == physmem_size)
-
+    
     ruby_profiler = RubyProfiler(num_of_sequencers = len(cpu_sequencers))
     
     ruby = RubySystem(clock = options.clock,
diff --git a/src/mem/protocol/MI_example-dir.sm 
b/src/mem/protocol/MI_example-dir.sm
--- a/src/mem/protocol/MI_example-dir.sm
+++ b/src/mem/protocol/MI_example-dir.sm
@@ -98,15 +98,18 @@
 
     if (directory.isPresent(addr)) {
 
-      if (state == State:I)  {
-        assert(getDirectoryEntry(addr).Owner.count() == 0);
-        assert(getDirectoryEntry(addr).Sharers.count() == 0);
-      } else if (state == State:M) {
+      if (state == State:M) {
         assert(getDirectoryEntry(addr).Owner.count() == 1);
         assert(getDirectoryEntry(addr).Sharers.count() == 0);
       }
 
       getDirectoryEntry(addr).DirectoryState := state;
+    
+      if (state == State:I)  {
+        assert(getDirectoryEntry(addr).Owner.count() == 0);
+        assert(getDirectoryEntry(addr).Sharers.count() == 0);
+        directory.invalidateBlock(addr);
+      }
     }
   }
 
@@ -264,10 +267,6 @@
       }
   }
 
-  action(d_deallocateDirectory, "\d", desc="Deallocate Directory Entry") {
-      directory.invalidateBlock(address);
-  }
-
   action(e_ownerIsRequestor, "e", desc="The owner is now the requestor") {
     peek(requestQueue_in, RequestMsg) {
       getDirectoryEntry(address).Owner.clear();
@@ -527,7 +526,6 @@
   transition(M_DRDI, Memory_Ack, I) {
     l_sendWriteBackAck;
     w_deallocateTBE;   
-    d_deallocateDirectory;
     l_popMemQueue;
   }
 
@@ -550,7 +548,6 @@
     l_sendWriteBackAck;
     da_sendDMAAck;
     w_deallocateTBE;
-    d_deallocateDirectory;
     l_popMemQueue;
   }
 
@@ -572,7 +569,6 @@
     w_writeDataToMemoryFromTBE;
     l_sendWriteBackAck;
     w_deallocateTBE;
-    d_deallocateDirectory;
     l_popMemQueue;
   }
 
diff --git a/src/mem/ruby/system/DirectoryMemory.cc 
b/src/mem/ruby/system/DirectoryMemory.cc
--- a/src/mem/ruby/system/DirectoryMemory.cc
+++ b/src/mem/ruby/system/DirectoryMemory.cc
@@ -51,14 +51,24 @@
     m_version = p->version;
     m_size_bytes = p->size;
     m_size_bits = log_int(m_size_bytes);
+    m_num_entries = 0;
+    m_use_map = p->use_map;
+    m_map_levels = p->map_levels;
 }
 
 void DirectoryMemory::init()
 {
   m_num_entries = m_size_bytes / RubySystem::getBlockSizeBytes();
-  m_entries = new Directory_Entry*[m_num_entries];
-  for (int i=0; i < m_num_entries; i++)
-    m_entries[i] = NULL;
+
+  if (m_use_map == false) {
+      m_entries = new Directory_Entry*[m_num_entries];
+      for (int i=0; i < m_num_entries; i++)
+          m_entries[i] = NULL;
+  } else {
+      int entry_bits = log_int(m_num_entries);
+      assert(entry_bits >= m_map_levels);
+      m_sparseMemory = new SparseMemory(entry_bits, m_map_levels);
+  }
 
   m_ram = g_system_ptr->getMemoryVector();
 
@@ -70,13 +80,15 @@
 DirectoryMemory::~DirectoryMemory()
 {
   // free up all the directory entries
-  for (uint64 i=0;i<m_num_entries;i++) {
-    if (m_entries[i] != NULL) {
-      delete m_entries[i];
-    }
-  }
   if (m_entries != NULL) {
-    delete [] m_entries;
+      for (uint64 i=0;i<m_num_entries;i++) {
+          if (m_entries[i] != NULL) {
+              delete m_entries[i];
+          }
+      }
+      delete [] m_entries;
+  } else if (m_use_map) {
+      delete m_sparseMemory;
   }
 }
 
@@ -102,14 +114,14 @@
         << "-" << RubySystem::getBlockSizeBits() << endl;
   }
   out << "  total memory size bytes: " << m_total_size_bytes << endl;
-  out << "  total memory size bits: " << log_int(m_total_size_bytes) << endl;
+  out << "  total memory bits: " << log_int(m_total_size_bytes) << endl;
 
 }
 
-int DirectoryMemory::mapAddressToDirectoryVersion(PhysAddress address)
+uint64 DirectoryMemory::mapAddressToDirectoryVersion(PhysAddress address)
 {
   if (m_num_directories_bits == 0) return 0;
-  int ret = address.bitSelect(RubySystem::getBlockSizeBits(),
+  uint64 ret = address.bitSelect(RubySystem::getBlockSizeBits(),
                               
RubySystem::getBlockSizeBits()+m_num_directories_bits-1);
   return ret;
 }
@@ -121,9 +133,11 @@
   return ret;
 }
 
-int DirectoryMemory::mapAddressToLocalIdx(PhysAddress address)
+uint64 DirectoryMemory::mapAddressToLocalIdx(PhysAddress address)
 {
-  int ret = address.getAddress() >> (RubySystem::getBlockSizeBits() + 
m_num_directories_bits);
+  uint64 ret = address.getAddress()                         \
+               >> static_cast<uint64>(RubySystem::getBlockSizeBits()
+                                      + m_num_directories_bits);
   return ret;
 }
 
@@ -131,13 +145,32 @@
 {
   assert(isPresent(address));
   Directory_Entry* entry;
-  int idx = mapAddressToLocalIdx(address);
-  entry = m_entries[idx];
-  if (entry == NULL) {
-    entry = new Directory_Entry;
-    entry->getDataBlk().assign(m_ram->getBlockPtr(address));
-    m_entries[idx] = entry;
+  uint64 idx;
+  DEBUG_EXPR(CACHE_COMP, HighPrio, address);
+
+  if (m_use_map) {
+    if (m_sparseMemory->exist(address)) {
+      entry = m_sparseMemory->lookup(address);
+      assert(entry != NULL);
+    } else {
+      //
+      // Note: SparseMemory internally creates a new Directory Entry
+      //
+      m_sparseMemory->add(address);
+      entry = m_sparseMemory->lookup(address);
+    }
+  } else {
+    idx = mapAddressToLocalIdx(address);
+    assert(idx < m_num_entries);
+    entry = m_entries[idx];
+
+    if (entry == NULL) {
+      entry = new Directory_Entry();
+      entry->getDataBlk().assign(m_ram->getBlockPtr(address));
+      m_entries[idx] = entry;
+    }
   }
+
   return (*entry);
 }
 /*
@@ -169,20 +202,29 @@
 
 void DirectoryMemory::invalidateBlock(PhysAddress address)
 {
+  
+  if (m_use_map) {
+    assert(m_sparseMemory->exist(address));
+    m_sparseMemory->remove(address);
+  }
   /*
-  assert(isPresent(address));
+  else {
+    assert(isPresent(address));
+    
+    Index index = address.memoryModuleIndex();
+    
+    if (index < 0 || index > m_size) {
+      ERROR_MSG("Directory Memory Assertion: accessing memory out of range.");
+    }
 
-  Index index = address.memoryModuleIndex();
-
-  if (index < 0 || index > m_size) {
-    ERROR_MSG("Directory Memory Assertion: accessing memory out of range.");
-  }
-
-  if(m_entries[index] != NULL){
-    delete m_entries[index];
-    m_entries[index] = NULL;
+    if(m_entries[index] != NULL){
+      delete m_entries[index];
+      m_entries[index] = NULL;
+    }
   }
   */
+
+
 }
 
 void DirectoryMemory::print(ostream& out) const
diff --git a/src/mem/ruby/system/DirectoryMemory.hh 
b/src/mem/ruby/system/DirectoryMemory.hh
--- a/src/mem/ruby/system/DirectoryMemory.hh
+++ b/src/mem/ruby/system/DirectoryMemory.hh
@@ -45,6 +45,7 @@
 #include "mem/protocol/Directory_Entry.hh"
 #include "sim/sim_object.hh"
 #include "params/RubyDirectoryMemory.hh"
+#include "mem/ruby/system/SparseMemory.hh"
 
 class DirectoryMemory : public SimObject {
 public:
@@ -57,9 +58,10 @@
   // Destructor
   ~DirectoryMemory();
 
-  int mapAddressToLocalIdx(PhysAddress address);
-  static int mapAddressToDirectoryVersion(PhysAddress address);
+  uint64 mapAddressToLocalIdx(PhysAddress address);
+  static uint64 mapAddressToDirectoryVersion(PhysAddress address);
 
+  bool isSparseImplementation() { return m_use_map; }
   uint64 getSize() { return m_size_bytes; }
 
   // Public Methods
@@ -86,7 +88,7 @@
   //  int m_size;  // # of memory module blocks this directory is responsible 
for
   uint64 m_size_bytes;
   uint64 m_size_bits;
-  int m_num_entries;
+  uint64 m_num_entries;
   int m_version;
 
   static int m_num_directories;
@@ -94,6 +96,9 @@
   static uint64_t m_total_size_bytes;
 
   MemoryVector* m_ram;
+  SparseMemory* m_sparseMemory;
+  bool m_use_map;
+  int m_map_levels;
 };
 
 // Output operator declaration
diff --git a/src/mem/ruby/system/DirectoryMemory.py 
b/src/mem/ruby/system/DirectoryMemory.py
--- a/src/mem/ruby/system/DirectoryMemory.py
+++ b/src/mem/ruby/system/DirectoryMemory.py
@@ -36,3 +36,5 @@
     cxx_class = 'DirectoryMemory'
     version = Param.Int(0, "")
     size = Param.MemorySize("1GB", "capacity in bytes")
+    use_map = Param.Bool(False, "enable sparse memory")
+    map_levels = Param.Int(4, "sparse memory map levels")
diff --git a/src/mem/ruby/system/SConscript b/src/mem/ruby/system/SConscript
--- a/src/mem/ruby/system/SConscript
+++ b/src/mem/ruby/system/SConscript
@@ -41,6 +41,7 @@
 
 Source('DMASequencer.cc')
 Source('DirectoryMemory.cc')
+Source('SparseMemory.cc')
 Source('CacheMemory.cc')
 Source('MemoryControl.cc')
 Source('MemoryNode.cc')
diff --git a/src/mem/ruby/system/SparseMemory.cc 
b/src/mem/ruby/system/SparseMemory.cc
new file mode 100644
--- /dev/null
+++ b/src/mem/ruby/system/SparseMemory.cc
@@ -0,0 +1,382 @@
+
+/*
+ * Copyright (c) 2009 Advanced Micro Devices, Inc.
+ * 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/SparseMemory.hh"
+
+
+// ****************************************************************
+
+
+SparseMemory::SparseMemory(int number_of_bits,
+                           int number_of_levels)
+{
+  int even_level_bits;
+  int extra;
+  m_total_number_of_bits = number_of_bits;
+  m_number_of_levels = number_of_levels;
+
+  //
+  // Create the array that describes the bits per level
+  //
+  m_number_of_bits_per_level = new int[m_number_of_levels];
+  even_level_bits = m_total_number_of_bits / m_number_of_levels;
+  extra = m_total_number_of_bits % m_number_of_levels;
+  for (int level = 0; level < m_number_of_levels; level++) {
+    if (level < extra)
+      m_number_of_bits_per_level[level] = even_level_bits + 1;
+    else
+      m_number_of_bits_per_level[level] = even_level_bits;
+  }
+  m_map_head = new m5::hash_map<Address, SparseMemEntry_t>;
+}
+
+SparseMemory::~SparseMemory()
+{
+  recursivelyRemoveTables(m_map_head, 0);
+  delete m_map_head;
+  delete [] m_number_of_bits_per_level;
+}
+
+// Recursively search table hierarchy for the lowest level table.
+// Delete the lowest table first, the tables above
+void SparseMemory::recursivelyRemoveTables(
+    m5::hash_map<Address, SparseMemEntry_t>* curTable,
+    int curLevel
+    )
+{
+    m5::hash_map<Address, SparseMemEntry_t>::iterator iter;
+
+  for (iter = curTable->begin(); iter != curTable->end(); iter++) {
+    SparseMemEntry_t* entryStruct = &((*iter).second);
+
+    if (curLevel != (m_number_of_levels - 1)) {
+      //
+      // If the not at the last level, analyze those lower level tables first,
+      // then delete those next tables
+      //
+      m5::hash_map<Address, SparseMemEntry_t>* nextTable;
+      nextTable = (m5::hash_map<Address, 
SparseMemEntry_t>*)(entryStruct->entry);
+      recursivelyRemoveTables(nextTable, (curLevel + 1));
+      delete nextTable;
+
+    } else {
+      //
+      // If at the last level, delete the directory entry
+      //
+      Directory_Entry* dirEntry;
+      dirEntry = (Directory_Entry*)(entryStruct->entry);
+      delete dirEntry;
+    }
+    entryStruct->entry = NULL;
+    //delete entryStruct;
+  }  
+
+  //
+  // Once all entries have been deleted, erase the entries
+  //
+  curTable->erase(curTable->begin(), curTable->end());
+}
+
+
+// PUBLIC METHODS
+
+// tests to see if an address is present in the memory
+bool SparseMemory::exist(const Address& address) const
+{
+  m5::hash_map<Address, SparseMemEntry_t>* curTable = m_map_head;
+  Address curAddress;
+
+  //
+  // Initiallize the high bit to be the total number of bits plus the block
+  // offset.  However the highest bit index is one less than this value.
+  //
+  int highBit = m_total_number_of_bits + RubySystem::getBlockSizeBits();
+  int lowBit;
+  assert(address == line_address(address));
+  DEBUG_EXPR(CACHE_COMP, HighPrio, address);
+
+  for (int level = 0; level < m_number_of_levels; level++) {
+    //
+    // Create the appropriate sub address for this level
+    // Note: that set Address is inclusive of the specified range, thus the 
+    // high bit is one less than the total number of bits used to create the 
+    // address.
+    //
+    lowBit = highBit - m_number_of_bits_per_level[level];
+    curAddress.setAddress(address.bitSelect(lowBit, highBit - 1));
+
+    DEBUG_EXPR(CACHE_COMP, HighPrio, level);
+    DEBUG_EXPR(CACHE_COMP, HighPrio, lowBit);
+    DEBUG_EXPR(CACHE_COMP, HighPrio, highBit - 1);
+    DEBUG_EXPR(CACHE_COMP, HighPrio, curAddress);
+
+    //
+    // Adjust the highBit value for the next level
+    //
+    highBit -= m_number_of_bits_per_level[level];
+    
+    //
+    // If the address is found, move on to the next level.  Otherwise,
+    // return not found
+    //
+    if (curTable->count(curAddress) != 0) {
+      curTable = (m5::hash_map<Address, 
SparseMemEntry_t>*)(((*curTable)[curAddress]).entry);
+    } else {
+      DEBUG_MSG(CACHE_COMP, HighPrio, "Not found");
+      return false;
+    }
+  }
+
+  DEBUG_MSG(CACHE_COMP, HighPrio, "Entry found");
+  return true;
+}
+
+// add an address to memory
+void SparseMemory::add(const Address& address)
+{
+  assert(address == line_address(address));
+  assert(exist(address) == false);
+
+  Address curAddress;
+  m5::hash_map<Address, SparseMemEntry_t>* curTable = m_map_head;
+  SparseMemEntry_t* entryStruct = NULL;
+
+  //
+  // Initiallize the high bit to be the total number of bits plus the block
+  // offset.  However the highest bit index is one less than this value.
+  //
+  int highBit = m_total_number_of_bits + RubySystem::getBlockSizeBits();
+  int lowBit;
+  void* newEntry = NULL;
+
+  for (int level = 0; level < m_number_of_levels; level++) {
+    //
+    // create the appropriate address for this level
+    // Note: that set Address is inclusive of the specified range, thus the 
+    // high bit is one less than the total number of bits used to create the 
+    // address.
+    //
+    lowBit = highBit - m_number_of_bits_per_level[level];
+    curAddress.setAddress(address.bitSelect(lowBit, highBit - 1));
+
+    //
+    // Adjust the highBit value for the next level
+    //
+    highBit -= m_number_of_bits_per_level[level];
+
+    //
+    // if the address exists in the cur table, move on.  Otherwise
+    // create a new table.
+    //
+    if (curTable->count(curAddress) != 0) {
+      curTable = (m5::hash_map<Address, 
SparseMemEntry_t>*)(((*curTable)[curAddress]).entry);
+    } else {
+
+      //
+      // if the last level, add a directory entry.  Otherwise add a map.
+      //
+      if (level == (m_number_of_levels - 1)) {
+        Directory_Entry* tempDirEntry = new Directory_Entry();
+        tempDirEntry->getDataBlk().clear();
+        newEntry = (void*)tempDirEntry;
+      } else {
+        m5::hash_map<Address, SparseMemEntry_t>* tempMap = new 
m5::hash_map<Address, SparseMemEntry_t>;
+        newEntry = (void*)(tempMap);
+      }
+
+      //
+      // Create the pointer container SparseMemEntry_t and add it to the table.
+      //
+      entryStruct = new SparseMemEntry_t;
+      entryStruct->entry = newEntry;
+      (*curTable)[curAddress] = *entryStruct;
+
+      //
+      // Move to the next level of the heirarchy
+      //
+      curTable = (m5::hash_map<Address, SparseMemEntry_t>*)newEntry;
+    }
+  }
+
+  assert(exist(address) != false);
+  return;
+}
+
+// recursively search table hierarchy for the lowest level table.
+// remove the lowest entry and any empty tables above it.
+int SparseMemory::recursivelyRemoveLevels(
+    const Address& address,
+    curNextInfo_t& curInfo)
+{
+  Address curAddress;
+  curNextInfo_t nextInfo;
+  SparseMemEntry_t* entryStruct;
+
+  //
+  // create the appropriate address for this level
+  // Note: that set Address is inclusive of the specified range, thus the 
+  // high bit is one less than the total number of bits used to create the 
+  // address.
+  //
+  curAddress.setAddress(address.bitSelect(curInfo.lowBit, 
+                                          curInfo.highBit - 1));
+
+  DEBUG_EXPR(CACHE_COMP, HighPrio, address);
+  DEBUG_EXPR(CACHE_COMP, HighPrio, curInfo.level);
+  DEBUG_EXPR(CACHE_COMP, HighPrio, curInfo.lowBit);
+  DEBUG_EXPR(CACHE_COMP, HighPrio, curInfo.highBit - 1);
+  DEBUG_EXPR(CACHE_COMP, HighPrio, curAddress);
+
+  assert(curInfo.curTable->count(curAddress) != 0);
+
+  entryStruct = &((*(curInfo.curTable))[curAddress]);
+
+  if (curInfo.level < (m_number_of_levels - 1)) {
+    //
+    // set up next level's info
+    //
+    nextInfo.curTable = (m5::hash_map<Address, 
SparseMemEntry_t>*)(entryStruct->entry);
+    nextInfo.level = curInfo.level + 1;
+    nextInfo.highBit = curInfo.highBit - 
m_number_of_bits_per_level[curInfo.level];
+    nextInfo.lowBit = curInfo.lowBit - 
m_number_of_bits_per_level[curInfo.level + 1];
+    
+    //
+    // recursively search the table hierarchy
+    //
+    int tableSize = recursivelyRemoveLevels(address, nextInfo);
+    
+    //
+    // If this table below is now empty, we must delete it and erase it from 
+    // our table.
+    //
+    if (tableSize == 0) {
+      delete nextInfo.curTable;
+      entryStruct->entry = NULL;
+      curInfo.curTable->erase(curAddress);
+      //delete entryStruct;
+    }
+  } else {
+    //
+    // if this is the last level, we have reached the Directory Entry and thus
+    // we should delete it including the SparseMemEntry container struct.
+    //
+    Directory_Entry* dirEntry;
+    dirEntry = (Directory_Entry*)(entryStruct->entry);
+    entryStruct->entry = NULL;
+    delete dirEntry;
+    curInfo.curTable->erase(curAddress);
+    //delete entryStruct;
+  }
+  return curInfo.curTable->size();
+
+}
+
+// remove an entry from the table
+void SparseMemory::remove(const Address& address)
+{
+  assert(address == line_address(address));
+  assert(exist(address) != false);
+
+  curNextInfo_t nextInfo;
+
+  //
+  // Initialize table pointer and level value
+  //
+  nextInfo.curTable = m_map_head;
+  nextInfo.level = 0;
+
+  //
+  // Initiallize the high bit to be the total number of bits plus the block
+  // offset.  However the highest bit index is one less than this value.
+  //
+  nextInfo.highBit = m_total_number_of_bits + RubySystem::getBlockSizeBits();
+  nextInfo.lowBit = nextInfo.highBit - m_number_of_bits_per_level[0];;
+
+  // 
+  // recursively search the table hierarchy for empty tables starting from the
+  // level 0.  Note we do not check the return value because the head table is
+  // never deleted;
+  //
+  recursivelyRemoveLevels(address, nextInfo);
+
+  assert(exist(address) == false);
+  return;
+}
+
+// looks an address up in memory
+Directory_Entry* SparseMemory::lookup(const Address& address)
+{
+  assert(exist(address) != false);
+  assert(address == line_address(address));
+
+  Address curAddress;
+  m5::hash_map<Address, SparseMemEntry_t>* curTable = m_map_head;
+  Directory_Entry* entry = NULL;
+
+  //
+  // Initiallize the high bit to be the total number of bits plus the block
+  // offset.  However the highest bit index is one less than this value.
+  //
+  int highBit = m_total_number_of_bits + RubySystem::getBlockSizeBits();
+  int lowBit;
+
+  for (int level = 0; level < m_number_of_levels; level++) {
+    //
+    // create the appropriate address for this level
+    // Note: that set Address is inclusive of the specified range, thus the 
+    // high bit is one less than the total number of bits used to create the 
+    // address.
+    //
+    lowBit = highBit - m_number_of_bits_per_level[level];
+    curAddress.setAddress(address.bitSelect(lowBit, highBit - 1));
+
+    //
+    // Adjust the highBit value for the next level
+    //
+    highBit -= m_number_of_bits_per_level[level];
+
+    //
+    // The entry should be in the table and valid
+    //
+    curTable = (m5::hash_map<Address, 
SparseMemEntry_t>*)(((*curTable)[curAddress]).entry);
+    assert(curTable != NULL);
+  }
+
+  //
+  // The last entry actually points to the Directory entry not a table
+  //
+  entry = (Directory_Entry*)curTable;
+
+  return entry;
+}
+
+void SparseMemory::print(ostream& out) const
+{
+}
+
diff --git a/src/mem/ruby/system/SparseMemory.hh 
b/src/mem/ruby/system/SparseMemory.hh
new file mode 100644
--- /dev/null
+++ b/src/mem/ruby/system/SparseMemory.hh
@@ -0,0 +1,109 @@
+
+/*
+ * Copyright (c) 2009 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef SPARSEMEMORY_H
+#define SPARSEMEMORY_H
+
+#include "mem/ruby/common/Global.hh"
+#include "base/hashmap.hh"
+#include "mem/ruby/common/Address.hh"
+#include "mem/protocol/Directory_Entry.hh"
+
+typedef struct SparseMemEntry {
+  void* entry;
+} SparseMemEntry_t;
+
+typedef struct curNextInfo {
+  m5::hash_map<Address, SparseMemEntry_t>* curTable;
+  int level;
+  int highBit;
+  int lowBit;
+} curNextInfo_t;
+
+class SparseMemory {
+public:
+
+  // Constructors
+  SparseMemory(int number_of_bits, int number_of_levels);
+
+  // Destructor
+  ~SparseMemory();
+
+  // Public Methods
+
+  void printConfig(ostream& out) { }
+
+  bool exist(const Address& address) const;
+  void add(const Address& address);
+  void remove(const Address& address);
+
+  Directory_Entry* lookup(const Address& address);
+
+  // Print cache contents
+  void print(ostream& out) const;
+private:
+  // Private Methods
+
+  // Private copy constructor and assignment operator
+  SparseMemory(const SparseMemory& obj);
+  SparseMemory& operator=(const SparseMemory& obj);
+
+  // Used by destructor to recursively remove all tables
+  void recursivelyRemoveTables(m5::hash_map<Address, SparseMemEntry_t>* 
currentTable,
+                              int level);
+
+  // recursive search for address and remove associated entries
+  int recursivelyRemoveLevels(const Address& address,
+                              curNextInfo_t& curInfo);
+
+  // Data Members (m_prefix)
+  m5::hash_map<Address, SparseMemEntry_t>* m_map_head;
+
+  int m_total_number_of_bits;
+  int m_number_of_levels;
+  int* m_number_of_bits_per_level;
+  
+  
+};
+
+// Output operator declaration
+ostream& operator<<(ostream& out, const SparseMemEntry& obj);
+
+// Output operator definition
+extern inline
+ostream& operator<<(ostream& out, const SparseMemEntry& obj)
+{
+  out << "SparseMemEntry";
+  out << flush;
+  return out;
+}
+
+
+#endif //SPARSEMEMORY_H
diff --git a/src/mem/ruby/system/System.cc b/src/mem/ruby/system/System.cc
--- a/src/mem/ruby/system/System.cc
+++ b/src/mem/ruby/system/System.cc
@@ -76,7 +76,11 @@
     m_block_size_bits = log_int(m_block_size_bytes);
 
     m_memory_size_bytes = p->mem_size;
-    m_memory_size_bits = log_int(m_memory_size_bytes);
+    if (m_memory_size_bytes == 0) {
+        m_memory_size_bits = 0;
+    } else {
+        m_memory_size_bits = log_int(m_memory_size_bytes);
+    }
 
     m_network_ptr = p->network;
     g_debug_ptr = p->debug;
@@ -104,7 +108,10 @@
 
 RubySystem::~RubySystem()
 {
-
+  delete m_network_ptr;
+  delete m_profiler_ptr;
+  delete m_tracer_ptr;
+  delete m_mem_vec_ptr;
 }
 
 void RubySystem::printSystemConfig(ostream & out)

_______________________________________________
m5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/m5-dev

Reply via email to