- 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
