The Sparta Modeling Framework
Loading...
Searching...
No Matches
DataView.hpp
1// <DataView> -*- C++ -*-
2
3#pragma once
4
5#include <iostream>
6#include <ios>
7#include <iomanip>
8#include <math.h>
9
10#include "sparta/functional/ArchDataSegment.hpp"
11#include "sparta/functional/ArchData.hpp"
14
15
16namespace sparta
17{
28 {
29 public:
30
31 typedef ArchDataSegment::offset_type offset_type;
32 typedef ArchDataSegment::ident_type ident_type;
33 typedef uint32_t index_type;
34
37
39 static const std::string DATAVIEW_UNPLACED_STR;
40
65 ident_type id,
66 offset_type size,
67 ident_type subset_of=INVALID_ID,
68 offset_type subset_offset=0,
69 const uint8_t* initial_buf_le=nullptr) :
70 ArchDataSegment(data, size, id, subset_of, subset_offset),
71 adata_(data), offset_(0),
72 line_(0),
73 initial_buf_le_(initial_buf_le)
74 {
75 sparta_assert(data, "ArchData (data) must not be null");
76 static_assert(sizeof(uint64_t) > sizeof(index_type),
77 "Must have a type larger than index_type in order to "
78 "perform bounds checking on index values which must "
79 "support the entire range from 0 to the maximum value");
80
81 // Allowed, but no other segments can be a subset
82 //if(id == INVALID_ID){
83 // throw SpartaException("Cannot construct DataView with identifier=INVALID_ID");
84 //}
85
86 if(subset_of == INVALID_ID && subset_offset != 0){
87 throw SpartaException("Cannot construct DataView with a valid identifier and nonzero offset: 0x")
88 << std::hex << subset_offset << ". Change subset_offset to 0 or set subset_of to INVALID_ID";
89 }
90
91 adata_->registerSegment(this); // Add self
92 }
93
94
95 // Attributes (non-virtual access)
96
98 ArchData* getArchData() const { return adata_; }
99
101 offset_type getSize() const { return getLayoutSize(); }
102
104 offset_type getOffset() const { return offset_; }
105
107 ArchData::Line* getLine() const { return line_; }
108
110 ident_type getID() const { return getLayoutID(); }
111
112
113 // I/O methods
114
141 template <typename T, ByteOrder BO=LE>
142 T read(index_type idx=0) const {
143 sparta_assert(idx < (getSize() / sizeof(T)), // Avoids overflow with large indexes
144 "read index " << idx << " and type " << demangle(typeid(T).name())
145 << " (size " << sizeof(T) << ") is invalid for this DataView of size " << getSize());
146 return readUnsafe<T, BO>(idx);
147 }
148
154 template <typename T, ByteOrder BO=LE>
155 T readUnsafe(index_type idx=0) const {
156 sparta_assert(line_, "There is no line pointer set for this DataView. ArchData likely has not been laid out yet. Tree probably needs to be finalized first.");
157 return line_->read<T, BO>(offset_, idx);
158 }
159
171 template <typename T, ByteOrder BO=LE>
172 T readPadded(index_type idx=0) const {
173 sparta_assert(sizeof(T) * ((uint64_t)idx) <= getSize(),
174 "readPadded index " << idx << " and type " << demangle(typeid(T).name())
175 << " (size " << sizeof(T) << ") is invalid for this DataView of size " << getSize());
176 return readPaddedUnsafe<T, BO>(idx);
177 }
178
185 template <typename T, ByteOrder BO=LE>
187 sparta_assert(line_, "There is no line pointer set for this DataView. ArchData likely has not been laid out yet. Tree probably needs to be finalized first.");
188 offset_type max_bytes = getSize() - (sizeof(T) * idx); // Must always be a power of 2
189 sparta_assert(isPowerOf2(max_bytes));
190
191 T result;
192 if(max_bytes >= 8){
193 result = line_->read<uint64_t, BO>(offset_, idx);
194 }else if(max_bytes == 4){
195 result = line_->read<uint32_t, BO>(offset_, idx);
196 }else if(max_bytes == 2){
197 result = line_->read<uint16_t, BO>(offset_, idx);
198 }else if(max_bytes == 1){
199 result = line_->read<uint8_t, BO>(offset_, idx);
200 }else{
201 sparta_assert(max_bytes == 0);
202 result = 0;
203 }
204
205 return result;
206 }
207
236 template <typename T, ByteOrder BO=LE>
237 void write(T val, index_type idx=0) {
238 sparta_assert(idx < (getSize() / sizeof(T)), // Avoids overflow with large indexes
239 "write index " << idx << " and type " << demangle(typeid(T).name())
240 << " (size " << sizeof(T) << ") is invalid for this DataView of size " << getSize());
241
242 writeUnsafe<T, BO>(val, idx);
243 }
244
251 template <typename T, ByteOrder BO=LE>
252 void writeUnsafe(T val, index_type idx=0) {
253 sparta_assert(line_, "There is no line pointer set for this DataView. ArchData likely has not been laid out yet. Tree probably needs to be finalized first.");
254
255 line_->write<T, BO>(offset_, val, idx);
256 }
257
274 template <typename T, ByteOrder BO=LE>
275 void writeTruncated(T val, uint32_t idx=0) {
276 sparta_assert(sizeof(T) * ((uint64_t)idx) <= getSize(),
277 "writeTruncated index " << idx << " and type " << demangle(typeid(T).name())
278 << " (size " << sizeof(T) << ") is invalid for this DataView of size " << getSize());
279
280 writeTruncatedUnsafe<T, BO>(val, idx);
281 }
282
291 template <typename T, ByteOrder BO=LE>
292 void writeTruncatedUnsafe(T val, uint32_t idx=0) {
293 sparta_assert(line_, "There is no line pointer set for this DataView. ArchData likely has not been laid out yet. Tree probably needs to be finalized first.");
294 offset_type max_bytes = getSize() - (sizeof(T) * idx); // Must always be a power of 2
295 sparta_assert(isPowerOf2(max_bytes));
296
297 if(max_bytes >= 8){
298 line_->write<uint64_t, BO>(offset_, (uint64_t)val, idx);
299 }else if(max_bytes == 4){
300 line_->write<uint32_t, BO>(offset_, (uint32_t)val, idx);
301 }else if(max_bytes == 2){
302 line_->write<uint16_t, BO>(offset_, (uint16_t)val, idx);
303 }else if(max_bytes == 1){
304 line_->write<uint8_t, BO>(offset_, (uint8_t)val, idx);
305 }else{
306 sparta_assert(max_bytes == 0);
307 }
308 }
309
320 if(getSize() != rhp.getSize()){
321 throw SpartaException("Cannot copy data between DataViews using operator= because the sizes differ");
322 }
323 if(rhp.line_ == nullptr){
324 throw SpartaException("Cannot copy data between DataViews using operator= because the right-hand operand is not laid out");
325 }
326 if(line_ == nullptr){
327 throw SpartaException("Cannot copy data between DataViews using operator= because the left-hand operand is not laid out");
328 }
329
330 const uint8_t* const src = rhp.line_->getDataPointer(rhp.offset_);
331 line_->write(offset_, getSize(), src);
332
333 return *this;
334 }
335
347 std::string getByteString() const {
348 sparta_assert(isPlaced(), "DataView has not been placed");
349
350 std::stringstream o;
351 o.fill('0');
352 for(offset_type i=0; i<getSize(); ++i){
353 o << std::setw(2) << std::hex << (uint16_t)read<uint8_t, LE>(i) << ' ';
354 }
355 return o.str();
356 }
357
366 template <ByteOrder BO=LE>
367 std::string getValueAsString() const {
368 sparta_assert(isPlaced(), "DataView has not been placed");
369
370 std::stringstream ss;
371 ss << "0x" << std::hex << std::setw(getSize()*2) << std::setfill('0');
372 switch(getSize()){
373 case 1:
374 ss << (uint32_t)read<uint8_t, BO>();
375 break;
376 case 2:
377 ss << (uint32_t)read<uint16_t, BO>();
378 break;
379 case 4:
380 ss << read<uint32_t, BO>();
381 break;
382 default: // 8 or more bytes
383 assembleIndexedReadsToValue_<BO>(ss);
384 }
385 return ss.str();
386 }
387
388 protected:
389
393
400 virtual void place_(offset_type offset) override {
401 adata_->checkSegment(offset, getSize());
402 line_ = &adata_->getLine(offset);
403 offset_ = offset - line_->getOffset(); // Store locally for faster 'read' calls
404 }
405
410 virtual void writeInitial_() override {
411 // Write initial value
412 if(initial_buf_le_){
413#if __BYTE_ORDER == __LITTLE_ENDIAN
414 for(offset_type i=0; i<getSize(); ++i){
415 write<uint8_t>(initial_buf_le_[i], i);
416 }
417#else // #if __BYTE_ORDER == __LITTLE_ENDIAN
418 for(offset_type i=getSize(); i>0; --i){
419 write<uint8_t>(initial_buf_le_[i], i);
420 }
421#endif // else // #if __BYTE_ORDER == __LITTLE_ENDIAN
422 }
423 }
424
427
428 private:
429
434 template <ByteOrder BO=LE>
435 void assembleIndexedReadsToValue_(std::stringstream& ss) const {
436 ss << "<unknown byte-order: " << BO << ">";
437 }
438
439 ArchData* const adata_;
440 offset_type offset_;
441 ArchData::Line* line_;
442
447 const uint8_t* const initial_buf_le_;
448 }; // class DataView
449
450 template <>
451 inline void DataView::assembleIndexedReadsToValue_<LE>(std::stringstream& ss) const {
452 for(offset_type i=(getSize()/8); i>0; --i){
453 ss << std::setw(16) << read<uint64_t, LE>(i-1);
454 }
455 }
456
457 template <>
458 inline void DataView::assembleIndexedReadsToValue_<BE>(std::stringstream& ss) const {
459 for(offset_type i=0; i<getSize()/8; ++i){
460 ss << std::setw(16) << read<uint64_t, BE>(i);
461 }
462 }
463
464} // namespace sparta
465
467#define SPARTA_DATAVIEW_BODY \
468 const std::string sparta::DataView::DATAVIEW_UNPLACED_STR = "dataview-unplaced";
Set of macros for Sparta assertions. Caught by the framework.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
Exception class for all of Sparta.
static const ident_type INVALID_ID
Indicates an invalid ID for an ArchDataSegment or any refinement.
ident_type getLayoutID() const
Gets the layout Identifier of this segment.
offset_type getLayoutSize() const
Gets the layout size of this segment (number of bytes)
bool isPlaced() const
Has this segment been placed yet.
Line object which composes part of an entire ArchData.
Definition ArchData.hpp:158
void write(offset_type offset, const T &t, uint32_t idx=0)
Write to this line, reordering bytes based on byte order if required.
Definition ArchData.hpp:354
T read(offset_type offset, uint32_t idx=0) const
Read from this line, reordering bytes based on byte order if required.
Definition ArchData.hpp:316
const uint8_t * getDataPointer(offset_type offset) const
Gets a pointer to data within this line for direct read access.
Definition ArchData.hpp:395
offset_type getOffset() const
Offset into the owning ArchData.
Definition ArchData.hpp:279
Contains a set of contiguous line of architectural data which can be referred to by any architected o...
Definition ArchData.hpp:39
void registerSegment(ArchDataSegment *seg)
All constructed segments must register themselves through this method to be laid out within the ArchD...
Definition ArchData.hpp:534
void checkSegment(offset_type offset, offset_type size) const
Checks that a segment is valid within this archdata by its given offset and size.
Definition ArchData.hpp:896
Line & getLine(offset_type offset)
Gets the line associated with this offset, allocating a new line if necessary.
Definition ArchData.hpp:663
View into a backend block of memory in an ArchData.
Definition DataView.hpp:28
static const ident_type INVALID_ID
Invalid Identifier constant for a DataView.
std::string getValueAsString() const
Reads the value of this DataView and renders as a string in the specified Byte-Order as a prefixed he...
Definition DataView.hpp:367
uint32_t index_type
Type used for specifying index into this DataView during a read or write.
Definition DataView.hpp:33
ArchData::Line * getLine() const
Get already-placed line.
Definition DataView.hpp:107
ArchDataSegment::offset_type offset_type
Represents offset into ArchData.
Definition DataView.hpp:31
T read(index_type idx=0) const
Reads a value from this DataView at the specific index.
Definition DataView.hpp:142
void writeTruncatedUnsafe(T val, uint32_t idx=0)
Same behavior as writeTruncated bout without checking access bounds.
Definition DataView.hpp:292
offset_type getOffset() const
Definition DataView.hpp:104
ArchData * getArchData() const
Definition DataView.hpp:98
ArchDataSegment::ident_type ident_type
DataView identifiers (distinguishes views in the same ArchData)
Definition DataView.hpp:32
T readUnsafe(index_type idx=0) const
Same behavior as read but without checking access bounds.
Definition DataView.hpp:155
std::string getByteString() const
Dump data in this DataView as hex bytes in address order with a space between each pair.
Definition DataView.hpp:347
void writeTruncated(T val, uint32_t idx=0)
Writes value from this DataView using a type T which might be larger than the size of the DataView.
Definition DataView.hpp:275
virtual void place_(offset_type offset) override
Places this DataView within its ArchData.
Definition DataView.hpp:400
offset_type getSize() const
Definition DataView.hpp:101
DataView(ArchData *data, ident_type id, offset_type size, ident_type subset_of=INVALID_ID, offset_type subset_offset=0, const uint8_t *initial_buf_le=nullptr)
Construct a DataView.
Definition DataView.hpp:64
virtual void writeInitial_() override
Writes the initial value of this DataView into memory. This is guaranteed to be called after placemen...
Definition DataView.hpp:410
ident_type getID() const
Definition DataView.hpp:110
static const std::string DATAVIEW_UNPLACED_STR
String to show instead of a value when representing an unplaced dataview.
Definition DataView.hpp:39
void write(T val, index_type idx=0)
Writes a value to this DataView at the specific index.
Definition DataView.hpp:237
void writeUnsafe(T val, index_type idx=0)
Same behavior as write but without checking access bounds.
Definition DataView.hpp:252
T readPadded(index_type idx=0) const
Reads a value from this DataView using a type T which might be larger than the dataview.
Definition DataView.hpp:172
T readPaddedUnsafe(index_type idx=0) const
Same behavior as readPadded but without checking access bounds.
Definition DataView.hpp:186
DataView & operator=(const DataView &rhp)
Reads data from another dataview and writes that value to this DataView.
Definition DataView.hpp:319
Used to construct and throw a standard C++ exception. Inherits from std::exception.
Macros for handling exponential backoff.
std::string demangle(const std::string &name) noexcept
Demangles a C++ symbol.
Definition Utils.hpp:203
bool isPowerOf2(uint64_t x)
Determines if input is 0 or a power of 2.
Definition Utils.hpp:142