The Sparta Modeling Framework
Loading...
Searching...
No Matches
BlockingMemoryIFNode.hpp
Go to the documentation of this file.
1
7#pragma once
8
11#include "sparta/statistics/Counter.hpp"
13#include "sparta/log/NotificationSource.hpp"
15#include "sparta/memory/AddressTypes.hpp"
17
18namespace sparta
19{
20 namespace memory
21 {
39 {
40 public:
41
45
53 struct ReadAccess {
54
56 mem(_mem),
57 addr(0),
58 size(0),
59 data(nullptr),
60 in_supplement(nullptr),
61 out_supplement(nullptr)
62 { }
63
68
74
79
83 const uint8_t* data;
84
89 const void* in_supplement;
90
96 };
97
105
107 mem(_mem),
108 addr(0),
109 size(0),
110 prior(nullptr),
111 tried(nullptr),
112 in_supplement(nullptr),
113 out_supplement(nullptr)
114 { }
115
122
127
132
137 const uint8_t* prior;
138
143 const uint8_t* tried;
144
149 const void* in_supplement;
150
156 };
157
160
163
167
168 BlockingMemoryIFNode() = delete;
169
185 const std::string& name,
186 const std::string& group,
187 group_idx_type group_idx,
188 const std::string& desc,
189 addr_t block_size,
190 const DebugMemoryIF::AccessWindow& window,
191 TranslationIF* transif=nullptr) :
192 TreeNode(name, group, group_idx, desc),
193 BlockingMemoryIF(desc, block_size, window, transif),
194 prior_val_buffer_(new uint8_t[block_size]), // block_size assured nonzero from DebugMemoryIF ctor
195 sset_(this),
196 post_write_noti_(this, "post_write", "Notification immediately after the memory interface has been written", "post_write"),
198 post_read_noti_(this, "post_read", "Notification immediately after the memory interface has been read", "post_read"),
200 {
201 if(!parent){
202 throw SpartaException("BlockingMemoryIFNode must be constructed with a non-null parent");
203 }
204 setExpectedParent_(parent);
205
206 ctr_writes_ = &sset_.createCounter<sparta::Counter>("num_writes", "Number of writes attempted (num write calls)",
208 ctr_reads_ = &sset_.createCounter<sparta::Counter>("num_reads", "Number of reads attempted (num read calls)",
210
211 parent->addChild(this);
212 }
213
225 const std::string& name,
226 const std::string& desc,
227 addr_t block_size,
228 const AccessWindow& window,
229 TranslationIF* transif=nullptr) :
231 name,
234 desc,
235 block_size,
236 window,
237 transif)
238 { }
239
240 virtual ~BlockingMemoryIFNode() {}
241
244
248
263
278
281
285
286 //bool isWriteValid(addr_t addr, addr_t size) const noexcept {
287 // return isWriteValid_(addr, size);
288 //}
289 //bool isReadValid(addr_t addr, addr_t size) const noexcept {
290 // return isReadValid_(addr, size);
291 //}
292
295
299
322 virtual bool tryRead(addr_t addr,
323 addr_t size,
324 uint8_t *buf,
325 const void *in_supplement=nullptr,
326 void *out_supplement=nullptr) override {
327 ++*ctr_reads_;
328 if(__builtin_expect(doesAccessSpan(addr, size), 0)){
329 //BlockingMemoryIF base class seems to imply that throwing from a tryRead is invalid
330 //throw MemoryReadError(addr, size, "addr is in a different block than addr+size");
331 return false;
332 }
333 if(__builtin_expect(isInAccessWindows(addr, size) == false, 0)){
334 return false;
335 }
336 if(__builtin_expect(post_read_noti_.observed() == false, 1)){
337 return tryRead_(addr, size, buf, in_supplement, out_supplement); // Read and return if unobserved
338 }
339
340 bool result = tryRead_(addr, size, buf, in_supplement, out_supplement);
341
342 if(result){
343 ReadNotiSrc::data_type post_read_noti_data(this);
344 post_read_noti_data.addr = addr;
345 post_read_noti_data.size = size;
346 post_read_noti_data.data = buf;
347 post_read_noti_data.in_supplement = in_supplement;
348 post_read_noti_.postNotification(post_read_noti_data);
349 }
350
351 return result;
352 }
353
372 void read(addr_t addr,
373 addr_t size,
374 uint8_t *buf,
375 const void *in_supplement=nullptr,
376 void *out_supplement=nullptr) {
377 if(!tryRead(addr, size, buf, in_supplement, out_supplement)){
378 verifyNoBlockSpan(addr, size);
379 verifyInAccessWindows(addr, size);
380 throw MemoryReadError(addr, size, "Unknown reason");
381 }
382 }
383
405 virtual bool tryWrite(addr_t addr,
406 addr_t size,
407 const uint8_t *buf,
408 const void *in_supplement=nullptr,
409 void *out_supplement=nullptr) override {
410 ++*ctr_writes_;
411 if(__builtin_expect(doesAccessSpan(addr, size), 0)){
412 // BlockingMemoryIF base class claims that tryRead and tryWrite cannot throw
413 // throw MemoryWriteError(addr, size, "addr is in a different block than addr+size");
414 return false;
415 }
416 if(__builtin_expect(isInAccessWindows(addr, size) == false, 0)){
417 return false;
418 }
419 if(__builtin_expect(post_write_noti_.observed() == false, 1)){
420 return tryWrite_(addr, size, buf, in_supplement, out_supplement); // Write and return if unobserved
421 }
422
423 // peek into block-size buffer
424 if(!tryPeek(addr, size, prior_val_buffer_.get())){
425 return false;
426 }
427
428 bool result = tryWrite_(addr, size, buf, in_supplement, out_supplement);
429
430 if(result){
431 PostWriteNotiSrc::data_type post_write_noti_data(this);
432 post_write_noti_data.addr = addr;
433 post_write_noti_data.size = size;
434 post_write_noti_data.prior = prior_val_buffer_.get();
435 post_write_noti_data.tried = buf;
436 post_write_noti_data.in_supplement = in_supplement;
437 // A getInternalBuffer method seems appropriate here but is
438 // not used because no assumptions should be made about
439 // storage. So Memory implementation may not HAVE an
440 // internal buffer for this memory (e.g. memory mapped registers not
441 // contiguous)
442 // Instead, caller must peek themselves.
443 post_write_noti_.postNotification(post_write_noti_data);
444 }
445
446 return result;
447 }
448
468 void write(addr_t addr,
469 addr_t size,
470 const uint8_t *buf,
471 const void *in_supplement=nullptr,
472 void *out_supplement=nullptr) {
473 if(!tryWrite(addr, size, buf, in_supplement, out_supplement)){
474 verifyNoBlockSpan(addr, size);
475 verifyInAccessWindows(addr, size);
476 throw MemoryReadError(addr, size, "Unkonwn reason");
477 }
478 }
479
480
483
489 return sset_;
490 }
491
502 virtual std::string stringize(bool pretty=false) const override {
503 (void) pretty;
504 std::stringstream ss;
505 ss << "<" << getLocation() << " size:0x" << std::hex << total_range_ << " bytes>";
506 return ss.str();
507 }
508
515 std::unique_ptr<uint8_t[]> prior_val_buffer_;
516
520
521 StatisticSet sset_;
522 Counter* ctr_writes_;
523 Counter* ctr_reads_;
524
527
532
533 }; // class BlockingMemoryIFNode
534 } // namespace memory
535} // namespace sparta
File that contains BlockingMemoryIF.
File that contains some exception types related to memory interfaces.
Exception class for all of Sparta.
File that defines the StatisticSet class.
Basic Node framework in sparta device tree composite pattern.
@ COUNT_NORMAL
Counter counts the number of times something happens like one would expect. This is a weakly monotoni...
Represents a counter of type counter_type (uint64_t). 2 and greater than 0 with a ceiling specified....
Definition Counter.hpp:27
bool observed() const noexcept
Is this NotificationSourceBase being observed at this node or an ancestor of any distance.
A TreeNode that generates a specific type of notification which propagates up a tree of TreeNodes (us...
ReadAccess data_type
Type of notification data generated by this instance.
void postNotification(const NotificationDataT &data) const
Post with reference to data with parent as message origin.
Used to construct and throw a standard C++ exception. Inherits from std::exception.
Set of StatisticDef and CounterBase-derived objects for visiblility through a sparta Tree.
CounterT & createCounter(_Args &&... __args)
Allocates a Counter which is owned by this StatisticSet and deleted at its destruction.
Node in a composite tree representing a sparta Tree item.
Definition TreeNode.hpp:205
static const group_idx_type GROUP_IDX_NONE
GroupIndex indicating that a node has no group index because it belongs to no group.
Definition TreeNode.hpp:303
std::string getLocation() const override final
static constexpr char GROUP_NAME_NONE[]
Group name indicating that a node belongs to no group.
Definition TreeNode.hpp:314
void addChild(TreeNode *child, bool inherit_phase=true)
Adds a TreeNode to this node as a child.
uint32_t group_idx_type
Index within a group.
Definition TreeNode.hpp:261
void setExpectedParent_(const TreeNode *parent)
Tracks a node as an expected parent without actually adding this node as a child. This is used almost...
Pure-virtual memory interface that builds on the BlockingMemoryIF, acting as a TreeNode in the SPARTA...
NotificationSource< ReadAccess > ReadNotiSrc
Notification type for memory read accesses.
PostWriteNotiSrc::data_type post_write_noti_data_
Data associated with a post-write notification.
void read(addr_t addr, addr_t size, uint8_t *buf, const void *in_supplement=nullptr, void *out_supplement=nullptr)
Attempts to read memory.
BlockingMemoryIFNode(sparta::TreeNode *parent, const std::string &name, const std::string &desc, addr_t block_size, const AccessWindow &window, TranslationIF *transif=nullptr)
Constructor for single window without TreeNode group information.
ReadNotiSrc post_read_noti_
NotificationSource for post-read notifications.
virtual bool tryRead(addr_t addr, addr_t size, uint8_t *buf, const void *in_supplement=nullptr, void *out_supplement=nullptr) override
Attempt to read memory of size size at address addr.
void write(addr_t addr, addr_t size, const uint8_t *buf, const void *in_supplement=nullptr, void *out_supplement=nullptr)
Attempts to write memory.
std::unique_ptr< uint8_t[]> prior_val_buffer_
Buffer for holding prior memory data during post-write notifications in order to avoid re-allocating ...
PostWriteNotiSrc post_write_noti_
NotificationSource for post-write notifications.
ReadNotiSrc::data_type post_read_noti_data_
Data associated with a post-read notification.
virtual bool tryWrite(addr_t addr, addr_t size, const uint8_t *buf, const void *in_supplement=nullptr, void *out_supplement=nullptr) override
Attempt to write memory of size size at address addr.
NotificationSource< PostWriteAccess > PostWriteNotiSrc
Notification type for memory write accesses.
PostWriteNotiSrc & getPostWriteNotificationSource()
Returns the post-write notification-source node for this memory interface which can be used to observ...
BlockingMemoryIFNode(sparta::TreeNode *parent, const std::string &name, const std::string &group, group_idx_type group_idx, const std::string &desc, addr_t block_size, const DebugMemoryIF::AccessWindow &window, TranslationIF *transif=nullptr)
Construct a blocking memory interface that is also a sparta::TreeNode subclass.
ReadNotiSrc & getReadNotificationSource()
Returns the read notification-source node for this memory interface which can be used to observe writ...
StatisticSet & getStatisticSet()
Returns the StatisticSet published by this Node.
virtual std::string stringize(bool pretty=false) const override
Render description of this BlockingMemoryIF as a string.
Pure-virtual memory interface which represents a simple, immediately accessible (blocking) address-sp...
virtual bool tryRead_(addr_t addr, addr_t size, uint8_t *buf, const void *in_supplement, void *out_supplement)=0
Implements tryRead.
virtual bool tryWrite_(addr_t addr, addr_t size, const uint8_t *buf, const void *in_supplement, void *out_supplement)=0
Implements tryWrite.
Memory interface which represents a simple, immediately accessible (blocking) address-space with supp...
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...
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 total_range_
Range of addresses from highest accessible to lowest.
void verifyNoBlockSpan(addr_t addr, addr_t size) const
Verifies that the given address does not span block boundaries defined for 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.
Error while attempting to read 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.
Structure containing data for a Memory post-write notification.
void * out_supplement
Supplementary data-object associated with the memory transaction which caused this notification....
const void * in_supplement
Supplementary data-object associated with the memory transaction which caused this notification.
addr_t addr
Address of the access on this object.
const uint8_t * prior
Value which was written to mem. Size is size field.
const uint8_t * tried
Value that the write access attempted to write. Size is size field.
DebugMemoryIF *const mem
Register on which the write access took place.
Structure containing data for a Memory pre- or post-read notification.
const void * in_supplement
Supplementary data-object associated with the memory transaction which caused this notification.
addr_t addr
Address of the access from the perspective of the memory interface.
DebugMemoryIF *const mem
Memory interface on which the access took place.
const uint8_t * data
Data just read from mem. Size is size field.
void * out_supplement
Supplementary data-object associated with the memory transaction which caused this notification....
Defines an access window within this interface. Accesses through a memory interface are constrained t...