10#include "sparta/memory/AddressTypes.hpp"
150 block_size_(block_size),
154 sparta_assert(block_size > 0,
"block size must be greater than 0");
155 block_idx_rshift_ = (
addr_t)log2(block_size);
156 block_offset_mask_ = (1 << block_idx_rshift_) - 1;
233 const addr_t required_range = (end-start) + dest_start;
234 if(memif->
getRange() < required_range){
235 throw SpartaException(
"Total range of destination memory interface is ")
236 <<
"too small to contain all mappings from SimpleMemoryMap mapping "
237 <<
"[" << start <<
", " << end <<
") -> " << memif
238 <<
" with dest_start" << dest_start <<
". Mapped input range size "
239 <<
"exceeds memory interface (with range " << memif->
getRange()
240 <<
" by " << required_range - memif->
getRange();
248 for(
auto& m : mappings_) {
249 if(m->overlaps(start,end)){
251 << start <<
", " << end
252 <<
") which overlaps another. "
253 <<
" mapping occupying [" << m->start
254 <<
", " << m->end <<
")";
260 BinTreeNode* n = bintree_;
266 n = bintree_ =
new BinTreeNode(
nullptr, start);
271 if(n->dest !=
nullptr){
274 if(start < m->start){
277 }
else if(start >= m->
end){
282 << start <<
", " << end
283 <<
") in a range previously occupied by another. "
284 <<
"Destination found occupying [" << m->
start
285 <<
", " << m->
end <<
"). Found when placing left endpoint";
287 }
else if(n->separator == start){
292 }
else if(n->separator < start){
298 n->r =
new BinTreeNode(n, start);
311 n->l =
new BinTreeNode(n, start);
324 if(n->dest !=
nullptr){
330 }
else if(end > m->
end){
335 << std::hex << start <<
", " << end
336 <<
") in a range previously occupied by another. "
337 <<
"Destination found occupying [" << m->
start
338 <<
", " << m->
end <<
"). Found when placing right endpoint";
340 }
else if(n->separator == end){
345 }
else if(n->separator < start){
348 <<
" encountered when placing right endpoint cannot be less than the start of the range";
349 }
else if(n->separator == start){
357 n->r =
new BinTreeNode(n, end);
363 }
else if(n->separator < end){
365 << std::hex << start <<
", " << end
366 <<
") in a range previously occupied by another. "
367 <<
"Separator at " << n->separator
368 <<
" found occupying [" << min <<
", " << max <<
")";
378 n->l =
new BinTreeNode(n, end);
393 std::unique_ptr<Mapping> m(
new Mapping(start, end, memif, dest_start));
394 if(end <= n->separator){
398 n = findSeparatorNode_(bintree_, start);
400 n->r =
new BinTreeNode(n, std::move(m));
403 n->l =
new BinTreeNode(n, std::move(m));
406 }
else if(start >= n->separator){
410 n = findSeparatorNode_(bintree_, end);
412 n->l =
new BinTreeNode(n, std::move(m));
415 n->r =
new BinTreeNode(n, std::move(m));
420 << start <<
", " << end <<
"). Range somehow spanned a separator at " << n->separator <<
". This should not have occurred";
425 mappings_.push_back(n->dest.get());
434 bintree_->recursDump(o);
444 uint32_t desc_len = 1;
445 uint32_t start_len = 1;
446 uint32_t end_len = 1;
447 for(
const Mapping* m : mappings_){
448 desc_len = std::max<uint32_t>(m->memif->getDescription().size(), desc_len);
449 std::stringstream tmp;
450 tmp << std::showbase << std::hex << m->start;
451 start_len = std::max<uint32_t>(tmp.str().size(), start_len);
453 tmp << std::showbase << std::hex << m->end;
454 end_len = std::max<uint32_t>(tmp.str().size(), end_len);
458 std::vector<const Mapping*> sorted = mappings_;
460 std::sort(sorted.begin(), sorted.end(),
461 [](
const Mapping* m1,
const Mapping* m2){return m1->start < m2->start;});
464 for(
const Mapping* m : sorted){
465 o <<
"map: [" << std::hex << std::showbase << std::setw(start_len)
466 << m->start <<
", " << std::setw(end_len) << m->end
467 << std::noshowbase <<
") -> \"" << std::setw(desc_len)
468 << m->memif->getDescription() <<
"\" +0x" << m->dest_off<<
'\n';
494 BinTreeNode* n = bintree_;
503 }
else if(addr >= m->
end){
508 }
else if(addr >= n->separator){
526 const BinTreeNode* n = bintree_;
535 }
else if(addr >= m->
end){
540 }
else if(addr >= n->separator){
560 const addr_t end = addr+size;
562 const BinTreeNode* n = bintree_;
570 }
else if(addr >= m->
end){
572 }
else if(end <= m->end){
575 throw MemoryAccessError(addr, size,
"any",
"This access spans more than one mapping");
577 }
else if(addr >= n->separator){
583 throw MemoryAccessError(addr, size,
"any",
"No single mapping found for this address/size");
622 return num_mappings_;
654 std::stringstream ss;
655 ss <<
"<SimpleMemoryMap " << num_mappings_ <<
" mappings>";
670 BinTreeNode() =
delete;
673 BinTreeNode(
const BinTreeNode&) =
delete;
676 BinTreeNode& operator=(
const BinTreeNode&) =
delete;
683 BinTreeNode(BinTreeNode* p,
addr_t sep) :
698 BinTreeNode(BinTreeNode* p, Mapping* d) :
715 BinTreeNode(BinTreeNode* p, std::unique_ptr<Mapping>&& d) :
736 BinTreeNode* grandparent() {
738 return parent->parent;
747 BinTreeNode* uncle() {
748 BinTreeNode *g = grandparent();
765 void recursDump(std::ostream& o,
int depth=0)
const {
773 o <<
"map: [0x" << std::hex << dest->start <<
", 0x" << dest->end
774 <<
") -> memif:" << dest->memif <<
" \"" << dest->memif->getDescription() <<
"\" dest_offset=+0x" << dest->dest_off<<
'\n';
776 o <<
"sep: " << std::hex <<
"0x" << separator <<
'\n';
781 for(
int i=0; i<depth; ++i){
786 l->recursDump(o, depth+1);
791 for(
int i=0; i<depth; ++i){
796 r->recursDump(o, depth+1);
806 const std::unique_ptr<Mapping> dest;
814 void RBTreeFixup_(BinTreeNode* n){
819 while((bintree_ != n) && (n->parent->red)){
820 if(n->parent == n->parent->parent->l){
821 BinTreeNode* u = n->parent->parent->r;
824 n->parent->red =
false;
826 n->parent->parent->red =
true;
827 n = n->parent->parent;
830 if(n == n->parent->r){
836 n->parent->red =
false;
837 n->parent->parent->red =
true;
838 rotateRight_(n->parent->parent);
842 BinTreeNode* u = n->parent->parent->l;
844 n->parent->red =
false;
846 n->parent->parent->red =
true;
847 n = n->parent->parent;
849 if(n == n->parent->l){
853 n->parent->red =
false;
854 n->parent->parent->red =
true;
855 rotateLeft_(n->parent->parent);
860 bintree_->red =
false;
878 BinTreeNode* findSeparatorNode_(BinTreeNode* root,
addr_t addr) {
879 BinTreeNode* n = root;
882 const Mapping* m = n->dest.get();
885 }
else if(addr >= m->end){
888 throw SpartaException(
"Looking for a separator node at addr=")
889 << addr <<
" ended up within a mapping node";
891 }
else if(addr == n->separator){
893 }
else if(addr > n->separator){
905 void rotateLeft_(BinTreeNode* n){
908 BinTreeNode* pivot = n->r;
913 pivot->parent = n->parent;
915 if(n->parent ==
nullptr){
918 if(n == n->parent->l){
919 n->parent->l = pivot;
921 n->parent->r = pivot;
931 void rotateRight_(BinTreeNode* n){
934 BinTreeNode* pivot = n->l;
939 pivot->parent = n->parent;
941 if(n->parent ==
nullptr){
944 if(n == n->parent->r){
945 n->parent->r = pivot;
947 n->parent->l = pivot;
963 BinTreeNode* bintree_;
968 uint32_t num_mappings_;
974 std::vector<const Mapping*> mappings_;
986 addr_t block_offset_mask_;
File that contains BlockingMemoryIF.
File that contains some exception types related to memory interfaces.
std::ostream & operator<<(std::ostream &out, const sparta::memory::SimpleMemoryMap &mi)
SimpleMemoryMap stream operator.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
Used to construct and throw a standard C++ exception. Inherits from std::exception.
Pure-virtual memory interface which represents a simple, immediately accessible (blocking) address-sp...
addr_t getRange() const
Gets the total span of this interface's valid address range.
addr_t getBlockSize() const
Returns the block size of memory represented by this interface. Read and write accesses must not span...
Indicates that there was an issue accessing a SPARTA memory object or interface.
Memory mapping object which maps addresses onto block-aligned destinations, each of which is a Blocki...
void verifyHasMapping(addr_t addr, addr_t size) const
Determines if a mapping is valid or not.
void dumpTree(std::ostream &o) const
Dumps the tree to an ostream like a directory listing.
addr_t getBlockSize() const
Returns the block size of memory represented by this interface. Read and write accesses must not span...
const Mapping * findMapping(addr_t addr) const
std::pair< const BlockingMemoryIF *, addr_t > mapAddress(addr_t addr) const noexcept
Maps an input address to a destination interface and address within that destination interface.
Mapping * findMapping(addr_t addr)
Finds the Mapping object associated with an address.
BlockingMemoryIF * findInterface(addr_t addr)
Returns the destination memory interface associated with a mapping containing an address.
SimpleMemoryMap(addr_t block_size)
Construct a SimpleMemoryMap.
const std::vector< const Mapping * > & getMappings() const
Returns the vector of current mappings in the order added.
uint32_t getNumMappings() const
Returns the number of mappings successfully added to this map.
void dumpMappings(std::ostream &o) const
Dumps a list of mappings to an ostream with a newline after each mapping entry.
virtual ~SimpleMemoryMap()
Destructor.
void addMapping(addr_t start, addr_t end, BlockingMemoryIF *memif, addr_t dest_start)
Create a mapping from addresses entering this object to a destination memory interface.
std::string stringize(bool pretty=false) const
Render description of this SimpleMemoryMap as a string.
uint64_t addr_t
Type for generic address representation in generic interfaces, errors and printouts within SPARTA.
Macros for handling exponential backoff.
Represents a mapping between an input address and output address for use in a destination BlockingMem...
const addr_t start
Beginning of the mapping input range (inclusive)
bool contains(addr_t a) const noexcept
Returns true if a is in the range [start,end)
const addr_t dest_off
Offset into destination memory interface. This is an offset from 0 which is received when the input a...
addr_t mapAddress(addr_t input) const noexcept
Maps an input address to the address-space for the destination memory interface.
const addr_t end
End of the mapping input address range (exclusive)
BlockingMemoryIF *const memif
Memory interface mapped to (after add/sub are applied to address)
Mapping(addr_t _start, addr_t _end, BlockingMemoryIF *_memif, addr_t _dest_off)
construct a mapping using the same values received from SimpleMemoryMap::addMapping
bool overlaps(addr_t a, addr_t b) const noexcept
Returns true if any part of the range [a,b) is shared with range [start,end)