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
73 ident_type id,
74 offset_type size,
75 ident_type subset_of=INVALID_ID,
76 offset_type subset_offset=0,
77 const uint8_t* initial_buf_le=nullptr) :
78 ArchDataSegment(data, size, id, subset_of, subset_offset),
79 adata_(data), offset_(0),
80 line_(0),
81 initial_buf_le_(initial_buf_le)
82 {
83 sparta_assert(data, "ArchData (data) must not be null");
84 static_assert(sizeof(uint64_t) > sizeof(index_type),
85 "Must have a type larger than index_type in order to "
86 "perform bounds checking on index values which must "
87 "support the entire range from 0 to the maximum value");
88
89 // Allowed, but no other segments can be a subset
90 //if(id == INVALID_ID){
91 // throw SpartaException("Cannot construct DataView with identifier=INVALID_ID");
92 //}
93
94 if(subset_of == INVALID_ID && subset_offset != 0){
95 throw SpartaException("Cannot construct DataView with a valid identifier and nonzero offset: 0x")
96 << std::hex << subset_offset << ". Change subset_offset to 0 or set subset_of to INVALID_ID";
97 }
98
99 adata_->registerSegment(this); // Add self
100 }
101
102
103 // Attributes (non-virtual access)
104
106 ArchData* getArchData() const { return adata_; }
107
109 offset_type getSize() const { return getLayoutSize(); }
110
112 offset_type getOffset() const { return offset_; }
113
115 ArchData::Line* getLine() const { return line_; }
116
118 ident_type getID() const { return getLayoutID(); }
119
120
121 // I/O methods
122
149 template <typename T, ByteOrder BO=LE>
150 T read(index_type idx=0) const {
151 sparta_assert(idx < (getSize() / sizeof(T)), // Avoids overflow with large indexes
152 "read index " << idx << " and type " << demangle(typeid(T).name())
153 << " (size " << sizeof(T) << ") is invalid for this DataView of size " << getSize());
154 return readUnsafe<T, BO>(idx);
155 }
156
162 template <typename T, ByteOrder BO=LE>
163 T readUnsafe(index_type idx=0) const {
164 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.");
165 return line_->read<T, BO>(offset_, idx);
166 }
167
179 template <typename T, ByteOrder BO=LE>
180 T readPadded(index_type idx=0) const {
181 sparta_assert(sizeof(T) * ((uint64_t)idx) <= getSize(),
182 "readPadded index " << idx << " and type " << demangle(typeid(T).name())
183 << " (size " << sizeof(T) << ") is invalid for this DataView of size " << getSize());
184 return readPaddedUnsafe<T, BO>(idx);
185 }
186
193 template <typename T, ByteOrder BO=LE>
195 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.");
196 offset_type max_bytes = getSize() - (sizeof(T) * idx); // Must always be a power of 2
197 sparta_assert(isPowerOf2(max_bytes));
198
199 T result;
200 if(max_bytes >= 8){
201 result = line_->read<uint64_t, BO>(offset_, idx);
202 }else if(max_bytes == 4){
203 result = line_->read<uint32_t, BO>(offset_, idx);
204 }else if(max_bytes == 2){
205 result = line_->read<uint16_t, BO>(offset_, idx);
206 }else if(max_bytes == 1){
207 result = line_->read<uint8_t, BO>(offset_, idx);
208 }else{
209 sparta_assert(max_bytes == 0);
210 result = 0;
211 }
212
213 return result;
214 }
215
244 template <typename T, ByteOrder BO=LE>
245 void write(T val, index_type idx=0) {
246 sparta_assert(idx < (getSize() / sizeof(T)), // Avoids overflow with large indexes
247 "write index " << idx << " and type " << demangle(typeid(T).name())
248 << " (size " << sizeof(T) << ") is invalid for this DataView of size " << getSize());
249
250 writeUnsafe<T, BO>(val, idx);
251 }
252
259 template <typename T, ByteOrder BO=LE>
260 void writeUnsafe(T val, index_type idx=0) {
261 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.");
262
263 line_->write<T, BO>(offset_, val, idx);
264 }
265
282 template <typename T, ByteOrder BO=LE>
283 void writeTruncated(T val, uint32_t idx=0) {
284 sparta_assert(sizeof(T) * ((uint64_t)idx) <= getSize(),
285 "writeTruncated index " << idx << " and type " << demangle(typeid(T).name())
286 << " (size " << sizeof(T) << ") is invalid for this DataView of size " << getSize());
287
289 }
290
299 template <typename T, ByteOrder BO=LE>
300 void writeTruncatedUnsafe(T val, uint32_t idx=0) {
301 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.");
302 offset_type max_bytes = getSize() - (sizeof(T) * idx); // Must always be a power of 2
303 sparta_assert(isPowerOf2(max_bytes));
304
305 if(max_bytes >= 8){
306 line_->write<uint64_t, BO>(offset_, (uint64_t)val, idx);
307 }else if(max_bytes == 4){
308 line_->write<uint32_t, BO>(offset_, (uint32_t)val, idx);
309 }else if(max_bytes == 2){
310 line_->write<uint16_t, BO>(offset_, (uint16_t)val, idx);
311 }else if(max_bytes == 1){
312 line_->write<uint8_t, BO>(offset_, (uint8_t)val, idx);
313 }else{
314 sparta_assert(max_bytes == 0);
315 }
316 }
317
328 if(getSize() != rhp.getSize()){
329 throw SpartaException("Cannot copy data between DataViews using operator= because the sizes differ");
330 }
331 if(rhp.line_ == nullptr){
332 throw SpartaException("Cannot copy data between DataViews using operator= because the right-hand operand is not laid out");
333 }
334 if(line_ == nullptr){
335 throw SpartaException("Cannot copy data between DataViews using operator= because the left-hand operand is not laid out");
336 }
337
338 const uint8_t* const src = rhp.line_->getDataPointer(rhp.offset_);
339 line_->write(offset_, getSize(), src);
340
341 return *this;
342 }
343
355 std::string getByteString() const {
356 sparta_assert(isPlaced(), "DataView has not been placed");
357
358 std::stringstream o;
359 o.fill('0');
360 for(offset_type i=0; i<getSize(); ++i){
361 o << std::setw(2) << std::hex << (uint16_t)read<uint8_t, LE>(i) << ' ';
362 }
363 return o.str();
364 }
365
374 template <ByteOrder BO=LE>
375 std::string getValueAsString() const {
376 sparta_assert(isPlaced(), "DataView has not been placed");
377
378 std::stringstream ss;
379 ss << "0x" << std::hex << std::setw(getSize()*2) << std::setfill('0');
380 switch(getSize()){
381 case 1:
382 ss << (uint32_t)read<uint8_t, BO>();
383 break;
384 case 2:
385 ss << (uint32_t)read<uint16_t, BO>();
386 break;
387 case 4:
388 ss << read<uint32_t, BO>();
389 break;
390 default: // 8 or more bytes
391 assembleIndexedReadsToValue_<BO>(ss);
392 }
393 return ss.str();
394 }
395
396 protected:
397
401
408 virtual void place_(offset_type offset) override {
409 adata_->checkSegment(offset, getSize());
410 line_ = &adata_->getLine(offset);
411 offset_ = offset - line_->getOffset(); // Store locally for faster 'read' calls
412 }
413
418 virtual void writeInitial_() override {
419 // Write initial value
420 if(initial_buf_le_){
421#if __BYTE_ORDER == __LITTLE_ENDIAN
422 for(offset_type i=0; i<getSize(); ++i){
423 write<uint8_t>(initial_buf_le_[i], i);
424 }
425#else // #if __BYTE_ORDER == __LITTLE_ENDIAN
426 for(offset_type i=getSize(); i>0; --i){
427 write<uint8_t>(initial_buf_le_[i], i);
428 }
429#endif // else // #if __BYTE_ORDER == __LITTLE_ENDIAN
430 }
431 }
432
435
436 private:
437
442 template <ByteOrder BO=LE>
443 void assembleIndexedReadsToValue_(std::stringstream& ss) const {
444 ss << "<unknown byte-order: " << BO << ">";
445 }
446
447 ArchData* const adata_;
448 offset_type offset_;
449 ArchData::Line* line_;
450
455 const uint8_t* const initial_buf_le_;
456 }; // class DataView
457
458 template <>
459 inline void DataView::assembleIndexedReadsToValue_<LE>(std::stringstream& ss) const {
460 for(offset_type i=(getSize()/8); i>0; --i){
461 ss << std::setw(16) << read<uint64_t, LE>(i-1);
462 }
463 }
464
465 template <>
466 inline void DataView::assembleIndexedReadsToValue_<BE>(std::stringstream& ss) const {
467 for(offset_type i=0; i<getSize()/8; ++i){
468 ss << std::setw(16) << read<uint64_t, BE>(i);
469 }
470 }
471
472} // namespace sparta
473
475#define SPARTA_DATAVIEW_BODY \
476 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:551
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:913
Line & getLine(offset_type offset)
Gets the line associated with this offset, allocating a new line if necessary.
Definition ArchData.hpp:680
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:375
ArchData::Line * getLine() const
Get already-placed line.
Definition DataView.hpp:115
T read(index_type idx=0) const
Reads a value from this DataView at the specific index.
Definition DataView.hpp:150
void writeTruncatedUnsafe(T val, uint32_t idx=0)
Same behavior as writeTruncated bout without checking access bounds.
Definition DataView.hpp:300
offset_type getOffset() const
Definition DataView.hpp:112
ArchData * getArchData() const
Definition DataView.hpp:106
T readUnsafe(index_type idx=0) const
Same behavior as read but without checking access bounds.
Definition DataView.hpp:163
std::string getByteString() const
Dump data in this DataView as hex bytes in address order with a space between each pair.
Definition DataView.hpp:355
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:283
virtual void place_(offset_type offset) override
Places this DataView within its ArchData.
Definition DataView.hpp:408
offset_type getSize() const
Definition DataView.hpp:109
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:72
virtual void writeInitial_() override
Writes the initial value of this DataView into memory. This is guaranteed to be called after placemen...
Definition DataView.hpp:418
ident_type getID() const
Definition DataView.hpp:118
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:245
ArchDataSegment::ident_type ident_type
DataView identifiers (distinguishes views in the same ArchData)
Definition DataView.hpp:32
void writeUnsafe(T val, index_type idx=0)
Same behavior as write but without checking access bounds.
Definition DataView.hpp:260
ArchDataSegment::offset_type offset_type
Represents offset into ArchData.
Definition DataView.hpp:31
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:180
uint32_t index_type
Type used for specifying index into this DataView during a read or write.
Definition DataView.hpp:33
T readPaddedUnsafe(index_type idx=0) const
Same behavior as readPadded but without checking access bounds.
Definition DataView.hpp:194
DataView & operator=(const DataView &rhp)
Reads data from another dataview and writes that value to this DataView.
Definition DataView.hpp:327
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:214
bool isPowerOf2(uint64_t x)
Determines if input is 0 or a power of 2.
Definition Utils.hpp:153