The Sparta Modeling Framework
Loading...
Searching...
No Matches
DebugMemoryIF.hpp
Go to the documentation of this file.
1
7#pragma once
8
9#include <math.h>
10
14#include "sparta/memory/TranslationIF.hpp"
15#include "sparta/memory/AddressTypes.hpp"
16#include "sparta/utils/StringManager.hpp"
17#include "sparta/utils/Utils.hpp"
18
19namespace sparta
20{
21 namespace memory
22 {
65 {
66 public:
67
71
78 struct AccessWindow {
79
80 AccessWindow() = delete;
81 AccessWindow& operator=(const AccessWindow&) = delete;
82
86 AccessWindow(const AccessWindow&) = default;
87
99 addr_t _end,
100 const std::string& _name="default") :
101 start(_start), end(_end), name(_name)
102 {
103 if(start >= end){
104 throw SpartaException("Cannot construct a Memory AccessWindow \"")
105 << name << "\" where start address (0x"
106 << std::hex << start << ") >= end address (0x" << end << ")";
107 }
108 }
109
114 bool containsAddr(addr_t addr) const noexcept {
115 return addr >= start && addr < end;
116 }
117
122
126 const addr_t end;
127
131 const std::string name;
132 };
133
136
140
144 DebugMemoryIF() = delete;
145
163 DebugMemoryIF(const std::string& desc,
164 addr_t block_size,
165 const AccessWindow& window,
166 TranslationIF* transif=nullptr) :
167 block_size_(block_size),
168 block_mask_(0),
170 acc_windows_({window}),
171 trans_(transif),
172 desc_ptr_(StringManager::getStringManager().internString(desc))
173 // total_range_, low_end_, high_end_, and accessible_size_ are initialized in body
174 {
175 // Validate block_size
176 if(block_size_ == 0){
177 throw SpartaException("0 block size specified for DebugMemoryIF: ")
178 << desc;
179 }
180
181 if(isPowerOf2(block_size_) == false){
182 throw SpartaException("block size (")
183 << block_size_ << ") specified is not a power of 2 for DebugMemoryIF: "
184 << desc;
185 }
186
187 // Compute block mask / idx_lsb
188 block_idx_lsb_ = (addr_t)log2(block_size);
189 block_mask_ = ~(((addr_t)1 << block_idx_lsb_) - 1);
191
192 // Validate access windows
193
194 if(acc_windows_.size() == 0){
195 throw SpartaException("0 access windows specified for DebugMemoryIF: ")
196 << desc;
197 }
198
200
201 low_end_ = acc_windows_[0].start;
202 high_end_ = acc_windows_[0].end;
203
204 // Check window block alignment
205 for(const auto& win : acc_windows_){
206 if(win.start % block_size != 0){
207 throw SpartaException("Memory AccessWindow start address was not block-size (")
208 << block_size << ") aligned. Was " << std::hex << win.start;
209 }
210 if(win.end % block_size != 0){
211 throw SpartaException("Memory AccessWindow end address was not block-size (")
212 << block_size << ") aligned. Was " << std::hex << win.end;
213 }
214
215 if(win.start < low_end_){
216 low_end_ = win.start;
217 }
218 if(win.end > high_end_){
219 high_end_ = win.end;
220 }
221 }
222
223 sparta_assert(acc_windows_.size() == 1); // Assumption for the following code
225 total_range_ = acc_windows_[acc_windows_.size()-1].end - acc_windows_[0].start;
226 accessible_size_ = total_range_; // For a single window
227 }
228
232 virtual ~DebugMemoryIF() {}
233
236
240
254 return trans_;
255 }
256
259
263
267 const std::string& getDescription() { return *desc_ptr_; };
268
274 addr_t getBlockSize() const { return block_size_; }
275
283 addr_t getRange() const { return total_range_; }
284
288 addr_t getLowEnd() const { return low_end_; }
289
293 addr_t getHighEnd() const { return high_end_; }
294
300 addr_t getAccessibleSize() const { return accessible_size_; } // sum of all window sizes
301
308 const std::vector<AccessWindow>& getWindows() const {
309 return acc_windows_;
310 }
311
314
318
326 bool isAddressInWindows(addr_t addr) const noexcept {
327 for(const auto& win : acc_windows_){
328 if(win.containsAddr(addr)){
329 return true;
330 }
331 }
332 return false;
333 }
334
344 void verifyInAccessWindows(addr_t addr, addr_t size) const {
345 // Assumes 1 access window
346 sparta_assert(acc_windows_.size() == 1); // This code is invalid once more than 1 window is supported
347 if(__builtin_expect(addr < acc_windows_[0].start || addr+size > acc_windows_[0].end, 0)){
348 MemoryAccessError ex(addr, size, "any", "The access at does not fit within access windows: ");
349 ex << "{ [" << acc_windows_[0].start << "," << acc_windows_[0].end << ") }";
350 throw ex;
351 }
352 }
353
363 bool isInAccessWindows(addr_t addr, addr_t size) const {
364 // Assumes 1 access window
365 sparta_assert(acc_windows_.size() == 1); // This code is invalid once more than 1 window is supported
366 return addr >= acc_windows_[0].start && addr+size <= acc_windows_[0].end;
367 }
368
377 void verifyNoBlockSpan(addr_t addr, addr_t size) const {
378 sparta_assert(size > 0);
379 if(__builtin_expect(doesAccessSpan(addr,size), 0)){
380 throw MemoryAccessError(addr, size, "any", "The access spans blocks");
381 }
382 }
383
394 bool doesAccessSpan(addr_t addr, addr_t size) const noexcept {
395 return (addr & block_mask_) != ((addr + size - 1) & block_mask_);
396 }
397
400
404
432 bool tryPeek(addr_t addr,
433 addr_t size,
434 uint8_t *buf) const {
435 if(false == __builtin_expect(isInAccessWindows(addr, size), 0)){
436 return false;
437 }
438
439 uint8_t* out = buf;
440 addr_t a = addr;
441 const addr_t end = addr + size;
442 while(1){
443 addr_t block_end = block_mask_ & (a + block_size_);
444 if(block_end >= end){
445 return tryPeek_(a, end - a, out);
446 }
447
448 addr_t size_in_block = block_end - a;
449 if(!tryPeek_(a, size_in_block, out)){
450 return false;
451 }
452 out += size_in_block;
453 a = block_end;
454 }
455 }
456
461 void peek(addr_t addr,
462 addr_t size,
463 uint8_t *buf) const {
464 if(!tryPeek(addr, size, buf)){
465 verifyInAccessWindows(addr, size);
466 throw MemoryPeekError(addr, size, "Cannot peek memory");
467 }
468 }
469
502 bool tryPoke(addr_t addr,
503 addr_t size,
504 const uint8_t *buf) {
505 if(false == __builtin_expect(isInAccessWindows(addr, size), 0)){
506 return false;
507 }
508
509 const uint8_t* in = buf;
510 addr_t a = addr;
511 const addr_t end = addr + size;
512 while(1){
513 addr_t block_end = block_mask_ & (a + block_size_);
514 if(block_end >= end){
515 return tryPoke_(a, end - a, in);
516 }
517
518 addr_t size_in_block = block_end - a;
519 if(!tryPoke_(a, size_in_block, in)){
520 return false;
521 }
522 in += size_in_block;
523 a = block_end;
524 }
525 }
526
531 void poke(addr_t addr,
532 addr_t size,
533 const uint8_t *buf) {
534 if(!tryPoke(addr, size, buf)){
535 verifyInAccessWindows(addr, size);
536 throw MemoryPokeError(addr, size, "Cannot poke memory");
537 }
538 }
539
542
543 protected:
544
549
555
560
564 const std::vector<AccessWindow> acc_windows_;
565
571
575 const std::string* const desc_ptr_;
576
581
586
591
596
597
598 private:
599
614 virtual bool tryPeek_(addr_t addr,
615 addr_t size,
616 uint8_t *buf) const = 0;
617
631 virtual bool tryPoke_(addr_t addr,
632 addr_t size,
633 const uint8_t *buf) = 0;
634
635 }; // class DebugMemoryIF
636 } // namespace memory
637} // namespace sparta
File that contains some exception types related to memory interfaces.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
Exception class for all of Sparta.
Basic Node framework in sparta device tree composite pattern.
Used to construct and throw a standard C++ exception. Inherits from std::exception.
static StringManager & getStringManager()
Returns the StringManager singleton.
Memory interface which represents a simple, immediately accessible (blocking) address-space with supp...
virtual ~DebugMemoryIF()
Virutal destructor.
addr_t high_end_
Highest accessible address + 1.
bool tryPeek(addr_t addr, addr_t size, uint8_t *buf) const
Attempts to 'peek' memory without having any side effects, size-limitations, alignment constraints ex...
DebugMemoryIF(const std::string &desc, addr_t block_size, const AccessWindow &window, TranslationIF *transif=nullptr)
Construct a DebugMemoryInterface.
const std::string & getDescription()
Returns the description specified at construction.
virtual const TranslationIF * getTranslationIF()
Gets the translation interface associated with this Debug memory interface (if any).
bool doesAccessSpan(addr_t addr, addr_t size) const noexcept
Determines if the given address spans block boundaries defined for this interface....
bool isInAccessWindows(addr_t addr, addr_t size) const
Determines if the range [addr, addr+size) is within the access windows for this interface.
addr_t getAccessibleSize() const
Gets the total accessible size of this interface's valid addresses within the total size (getRange) e...
addr_t accessible_size_
Number of bytes accessible through this interface.
addr_t getHighEnd() const
Gets the highest address accessible + 1.
addr_t total_range_
Range of addresses from highest accessible to lowest.
const addr_t block_size_
Size of a block accessed through this interface.
addr_t block_mask_
Mask applied to an address to get only bits representing the block ID.
addr_t getLowEnd() const
Gets the lowest address accessible.
addr_t getRange() const
Gets the total span of this interface's valid address range.
TranslationIF * trans_
Translation interface created for this interface. Externally owned.
bool isAddressInWindows(addr_t addr) const noexcept
Determines if the given address is in an access window defined for this interface.
void poke(addr_t addr, addr_t size, const uint8_t *buf)
Wrapper on tryPoke which throws a MemoryAccessError if the poke is not legal.
addr_t block_idx_lsb_
rshift applied to an address to get the block ID
void verifyNoBlockSpan(addr_t addr, addr_t size) const
Verifies that the given address does not span block boundaries defined for this interface.
const std::string *const desc_ptr_
Description pointer.
const std::vector< AccessWindow > & getWindows() const
Gets the vector of windows representing this interface.
void verifyInAccessWindows(addr_t addr, addr_t size) const
Verifies that the range [addr, addr+size) is within the access windows for this interface.
DebugMemoryIF()=delete
Default constuctor.
addr_t low_end_
Lowest accessible address.
const std::vector< AccessWindow > acc_windows_
Vector of access windows representing this memory.
void peek(addr_t addr, addr_t size, uint8_t *buf) const
Wrapper on tryPeek which throws a MemoryAccessError if the peek is not legal.
bool tryPoke(addr_t addr, addr_t size, const uint8_t *buf)
Attempts to 'poke' memory without having any side effects other than changing the bytes within the ra...
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.
Error while attempting to peek some memory object or interface.
Error while attempting to poke some memory object or interface.
Blocking translation interface with 1:1 translation unless subclassed.
uint64_t addr_t
Type for generic address representation in generic interfaces, errors and printouts within SPARTA.
Macros for handling exponential backoff.
bool isPowerOf2(uint64_t x)
Determines if input is 0 or a power of 2.
Definition Utils.hpp:142
Defines an access window within this interface. Accesses through a memory interface are constrained t...
AccessWindow(const AccessWindow &)=default
Default copy constructor.
bool containsAddr(addr_t addr) const noexcept
Does this window interval contain the specified post-translated address addr.
const addr_t start
inclusive start address (block-aligned)
const addr_t end
exclusive end address (block-aligned)
const std::string name
What is this window called (for printouts)
AccessWindow(addr_t _start, addr_t _end, const std::string &_name="default")
Construct address window with range.