- You have some more random whitespace changes in there.
- You seem to have made some changes to code that was commented out.
Can we just remove that code?
- Is SparseMemory a Ruby specific thing, or could it be moved to src/mem?
- Please use M5 style (4 space indent, function name at the beginning
of a line, etc.) on new files.

On Thu, Mar 18, 2010 at 2:46 PM, Brad Beckmann <[email protected]> wrote:
> # 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
>
>
_______________________________________________
m5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/m5-dev

Reply via email to