15#include "sparta/functional/DataView.hpp"
16#include "sparta/functional/RegisterBits.hpp"
17#include "sparta/utils/Utils.hpp"
18#include "sparta/log/NotificationSource.hpp"
138 RegisterBits computeFieldMask_(uint32_t start, uint32_t end, uint32_t reg_size)
140 const auto num_ones = start - end + 1;
145 const uint64_t masked_bits = std::numeric_limits<uint64_t>::max() &
146 (std::numeric_limits<uint64_t>::max() >> ((
sizeof(uint64_t) * CHAR_BIT) - num_ones));
147 mask.
set(masked_bits);
222 field_mask_(computeFieldMask_(def.high_bit, def.low_bit, reg_.
getNumBytes())),
223 not_field_mask_(~field_mask_)
227 sparta_assert(def_.
name != 0,
"Register::Field::Definition::name cannot be empty");
232 <<
") less than a low bit (" << def_.
low_bit <<
")";
238 <<
") greater than or equal to the number of bits in the register ("
244 <<
") greater than or equal to the number of bits in the register ("
251 <<
"Problem with field \"" <<
getLocation() <<
"\"";
290 write_(newRegisterValue_(t));
302 poke_(newRegisterValue_(t));
310 pokeUnmasked_(newRegisterValue_(t));
358 virtual std::string
stringize(
bool pretty=
false)
const override{
360 std::stringstream ss;
363 ss <<
" bits LE:0x" << std::hex <<
peek();
358 virtual std::string
stringize(
bool pretty=
false)
const override {
…}
375 reg_.
read(reg_bits.data(), reg_size_, 0);
382 reg_.peek(reg_bits.data(), reg_size_, 0);
386 void write_(
const RegisterBits &value)
388 reg_.
write(value.data(), value.getSize(), 0);
391 void poke_(
const RegisterBits &value)
393 reg_.
poke(value.data(), value.getSize(), 0);
396 void pokeUnmasked_(
const RegisterBits &value)
401 RegisterBits newRegisterValue_(
access_type value)
const
403 const auto old_register_value = peekBitArray_();
405 RegisterBits field_value_to_be_written_shifted(std::max((
size_t)reg_size_,
sizeof(
access_type)), value);
406 field_value_to_be_written_shifted <<=
getLowBit();
410 sparta_assert((field_value_to_be_written_shifted & not_field_mask_).none(),
411 "Value of " << value <<
" too large for bit field "
414 return (old_register_value & not_field_mask_) | field_value_to_be_written_shifted;
425 const Definition &def_;
435 const RegisterBits field_mask_;
440 const RegisterBits not_field_mask_;
490 :
reg(_reg),
prior(_prior_dview),
final(_final_dview)
611 const std::vector<Field::Definition>
fields;
724 NULL_TO_EMPTY_STR(def.name),
725 NULL_TO_EMPTY_STR(def.group),
727 NULL_TO_EMPTY_STR(def.desc),
730 bits_(def.bytes * 8),
731 mask_(computeWriteMask_(&def_)),
732 post_write_noti_(this,
734 "Notification immediately after the register has been written",
736 post_read_noti_(this,
738 "Notification immediately after the register has been read",
741 if(parent !=
nullptr){
745 sparta_assert(def.
name != 0,
"Cannot have a null name in a register definition");
750 <<
" but had group name \"\". A group name is required if a group number is specified.";
755 <<
getLocation() <<
"\" which had group number GROUP_NUM_NONE"
756 <<
" but had group name \"" << def.
group
757 <<
"\". A group number is required if a group name is specified.\"" <<
GROUP_NAME_NONE <<
"\"";
761 static_assert(std::is_unsigned<
decltype(def.
bytes)>::value ==
true);
764 <<
getName() <<
"\" size in bytes must be a power of 2 larger than 0, is "
769 for(
auto & fdp : def_.
fields){
774 const char*
const * ap = def_.
aliases;
783 if(parent !=
nullptr){
795 for(
Field* f : owned_fields_){
832 owned_fields_.push_back(
new Field(*
this, fd));
833 return owned_fields_.back();
981 template <
typename T>
985 read(&tmp,
sizeof(tmp), idx *
sizeof(tmp));
995 return read_with_check_cb_(
this);
1001 "read callback only support for 4- and 8-byte registers");
1011 template <
typename T>
1014 assert(isWritable());
1015 write(&val,
sizeof(val), idx *
sizeof(val));
1021 template <
typename T>
1024 assert(isWritable());
1026 static_assert((
sizeof(T)==4) || (
sizeof(T)==8),
1027 "write callback only support for 4- and 8-byte registers");
1028 return write_with_check_cb_(
this, val);
1039 template <
typename T>
1042 assert(isWritable());
1046 template <
typename T>
1050 peek(&tmp,
sizeof(tmp), idx *
sizeof(tmp));
1058 template <
typename T>
1061 assert(isWritable());
1062 poke(&val,
sizeof(val), idx *
sizeof(val));
1070 template <
typename T>
1073 assert(isWritable());
1080 template <
typename T>
1084 dmiRead_(&res,
sizeof(res),
sizeof(res) * idx);
1092 template <
typename T>
1095 assert(isWritable());
1096 dmiWrite_(&val,
sizeof(val),
sizeof(val) * idx);
1106 template <
typename T>
1110 return *(
reinterpret_cast<const T*
>(mask_.
data()) + idx);
1116 bool isWritable()
const
1139 std::vector<uint8_t> value(size);
1140 peek(value.data(), size, 0);
1141 return utils::bin_to_hexstr(value.data(), size);
1154 return utils::bin_to_hexstr(
1155 reinterpret_cast<const uint8_t *
>(mask_.
data()), mask_.
getSize());
1169 return utils::bin_to_bitstr(
1170 reinterpret_cast<const uint8_t *
>(mask_.
data()), mask_.
getSize());
1204 void read(
void *buf,
size_t size,
size_t offset)
1207 read_(buf, size, offset);
1210 void peek(
void *buf,
size_t size,
size_t offset)
const
1213 peek_(buf, size, offset);
1216 void write(
const void *buf,
size_t size,
size_t offset)
1218 assert(isWritable());
1220 RegisterBits val(
reinterpret_cast<const uint8_t *
>(buf), size);
1221 RegisterBits mask = mask_ >> 8 * offset;
1222 RegisterBits old = (peekRegisterBits_(size, offset) & ~mask) | (val & mask);
1223 write_(old.data(), size, offset);
1226 void writeUnmasked(
const void *buf,
size_t size,
size_t offset)
1228 assert(isWritable());
1230 write_(buf, size, offset);
1233 void poke(
const void *buf,
size_t size,
size_t offset)
1235 assert(isWritable());
1237 RegisterBits val(
reinterpret_cast<const uint8_t *
>(buf), size);
1238 RegisterBits mask = mask_ >> 8 * offset;
1239 RegisterBits old = (peekRegisterBits_(size, offset) & ~mask) | (val & mask);
1240 poke_(old.data(), size, offset);
1243 void pokeUnmasked(
const void *buf,
size_t size,
size_t offset)
1245 assert(isWritable());
1247 poke_(buf, size, offset);
1266 return post_write_noti_;
1282 return post_read_noti_;
1290 read_with_check_cb_ = callback;
1298 return read_with_check_cb_ !=
nullptr;
1306 write_with_check_cb_ = callback;
1314 return write_with_check_cb_ !=
nullptr;
1332 fields_.push_back(fld);
1336 virtual void read_(
void *buf,
size_t size,
size_t offset = 0) = 0;
1338 virtual void peek_(
void *buf,
size_t size,
size_t offset = 0)
const = 0;
1340 virtual void write_(
const void *buf,
size_t size,
size_t offset = 0) = 0;
1342 virtual void poke_(
const void *buf,
size_t size,
size_t offset = 0) = 0;
1344 virtual void dmiRead_(
void *buf,
size_t size,
size_t offset = 0)
const
1346 (void)buf; (void)size; (void)offset;
1350 virtual void dmiWrite_(
const void *buf,
size_t size,
size_t offset = 0)
1352 (void)buf; (void)size; (void)offset;
1357 RegisterBits computeWriteMask_(
const Definition *def)
const
1360 throw SpartaException(
"Register \"")
1361 <<
getName() <<
"\" size in bytes must be a power of 2 larger than 0, is "
1365 const auto mask_size = def->bytes;
1366 RegisterBits write_mask(mask_size);
1367 RegisterBits partial_mask(mask_size);
1368 partial_mask.fill(0xff);
1370 for (
auto &fdp : def->fields) {
1371 if (fdp.read_only) {
1372 const uint64_t field_size = fdp.high_bit - fdp.low_bit + 1;
1373 const uint64_t shift_down = 8 * mask_size - field_size;
1374 const uint64_t shift_up = fdp.low_bit;
1376 write_mask |= ((partial_mask >> shift_down) << shift_up);
1383 RegisterBits peekRegisterBits_(
size_t size,
size_t offset=0)
const
1385 RegisterBits bits(size);
1386 peek_(bits.data(), size, offset);
1393 const Definition def_;
1414 const RegisterBits mask_;
1433inline bool operator==(
const RegisterBase::Definition &a,
1434 const RegisterBase::Definition &b)
1439 if (!utils::strcmp_with_null(a.name, b.name)) {
1442 if (a.group_num != b.group_num) {
1445 if (!utils::strcmp_with_null(a.group, b.group)) {
1448 if (a.group_idx != b.group_idx) {
1451 if (!utils::strcmp_with_null(a.desc, b.desc)) {
1454 if (a.bytes != b.bytes) {
1460 if (a.bank_membership != b.bank_membership) {
1464 auto a_aliases = a.aliases;
1465 auto b_aliases = b.aliases;
1466 if (a_aliases !=
nullptr && b_aliases !=
nullptr) {
1467 for (; *a_aliases != 0 || *b_aliases != 0; ++a_aliases, ++b_aliases) {
1468 if (!utils::strcmp_with_null(*a_aliases, *b_aliases)) {
1472 }
else if (!(a_aliases ==
nullptr && b_aliases ==
nullptr)) {
1476 if (a.subset_of != b.subset_of) {
1479 if (!utils::strcmp_with_null((
const char *)a.initial_value, (
const char *)b.initial_value)) {
1482 if (a.hints != b.hints) {
1485 if (a.regdomain != b.regdomain) {
1492inline bool operator!=(
const RegisterBase::Definition &a,
1493 const RegisterBase::Definition &b)
1513 post_write_noti_data_(
this, &prior_val_dview_, &dview_),
1514 post_read_noti_data_(
this, &dview_)
1522 std::stringstream ss;
1543 template <
typename T>
1547 dmiReadImpl_(&res,
sizeof(res),
sizeof(res) * idx);
1557 template <
typename T>
1560 assert(isWritable());
1561 dmiWriteImpl_(&val,
sizeof(val),
sizeof(val) * idx);
1570 template <
typename T>
1573 assert(isWritable());
1574 dmiWriteImpl_(&val,
sizeof(T), idx);
1581 void onBindTreeEarly_()
override
1588 void read_(
void *buf,
size_t size,
size_t offset=0) override final
1592 peek_(buf, size, offset);
1594 post_read_noti.postNotification(post_read_noti_data_);
1598 void peek_(
void *buf,
size_t size,
size_t offset=0) const override final
1601 dview_.
getOffset() + offset, size,
static_cast<uint8_t *
>(buf));
1604 void dmiRead_(
void *buf,
size_t size,
size_t offset = 0) const override final
1606 dmiReadImpl_(buf, size, offset);
1609 void write_(
const void *buf,
size_t size,
size_t offset=0) override final
1611 assert(isWritable());
1615 prior_val_dview_ = dview_;
1616 poke_(buf, size, offset);
1617 post_write_noti.postNotification(post_write_noti_data_);
1619 poke_(buf, size, offset);
1623 void poke_(
const void *buf,
size_t size,
size_t offset=0) override final
1625 assert(isWritable());
1627 dview_.
getOffset() + offset, size,
static_cast<const uint8_t *
>(buf));
1630 void dmiWrite_(
const void *buf,
size_t size,
size_t offset = 0) override final
1632 assert(isWritable());
1633 dmiWriteImpl_(buf, size, offset);
1636 inline void dmiReadImpl_(
void *buf,
size_t size,
size_t offset = 0)
const
1638 memcpy(buf, raw_data_ptr_ + offset, size);
1641 inline void dmiWriteImpl_(
const void *buf,
size_t size,
size_t offset = 0)
1643 assert(isWritable());
1644 memcpy(raw_data_ptr_ + offset, buf, size);
1657 DataView prior_val_dview_;
1672 uint8_t *raw_data_ptr_ =
nullptr;
1713#define SPARTA_REGISTER_BODY \
1714 const sparta::RegisterBase::Definition sparta::RegisterBase::DEFINITION_END{0, nullptr, 0, nullptr, 0, nullptr, 0, { }, { }, nullptr, 0, 0, 0, 0, 0};
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.
#define SPARTA_EXPECT_FALSE(x)
A macro for hinting to the compiler a particular condition should be considered most likely false.
Exception class for all of Sparta.
Basic Node framework in sparta device tree composite pattern.
File that defines a ValidValue.
bool isPlaced() const
Has this segment been placed yet.
uint8_t * getRawDataPtr(const offset_type offset)
return the raw data pointer for this line for direct read and write. No error checking is performed....
void write(offset_type offset, const T &t, uint32_t idx=0)
Write to this line, reordering bytes based on byte order if required.
T read(offset_type offset, uint32_t idx=0) const
Read from this line, reordering bytes based on byte order if required.
void flagDirty()
Allows caller to explicitly flag this line as dirty.
Contains a set of contiguous line of architectural data which can be referred to by any architected o...
bool isLaidOut() const
Has this ArchData been laid out yet.
View into a backend block of memory in an ArchData.
static const ident_type INVALID_ID
Invalid Identifier constant for a DataView.
ArchData::Line * getLine() const
Get already-placed line.
offset_type getOffset() const
ArchData * getArchData() const
static const std::string DATAVIEW_UNPLACED_STR
String to show instead of a value when representing an unplaced dataview.
ArchDataSegment::ident_type ident_type
DataView identifiers (distinguishes views in the same ArchData)
ArchDataSegment::offset_type offset_type
Represents offset into ArchData.
uint32_t index_type
Type used for specifying index into this DataView during a read or write.
A TreeNode that generates a specific type of notification which propagates up a tree of TreeNodes (us...
PostWriteAccess data_type
virtual bool isBuilt() const
Is this node (and thus the entire tree above it) "built". Checks that getPhase has passed TREE_BUILDI...
Register Field with masked access to owning register.
size_type getNumBits() const
Gets number of bits in this field.
void write(access_type t)
Write the field.
const Definition & getDefinition() const
Gets the Definition with which this Field was constructed.
access_type peek() const
Peeks the field.
size_type getHighBit() const
Returns the index of the high bit (inclusive) in this field.
virtual std::string stringize(bool pretty=false) const override
Create a string representation of this node.
static const size_type MAX_FIELD_BITS
Maximum number of bits allowed in a field.
uint64_t access_type
Type used for bitfield access.
void pokeUnmasked(access_type t)
Poke the field without any read-only mask being applied.
Field(RegisterBase ®, const Definition &def)
Field Constructor.
access_type read()
Read the field.
bool isReadOnly() const
Returns true if this field is marked read-only.
size_type getLowBit() const
Returns the index of the low bit (inclusive) in this field.
void poke(access_type t)
Poke the field.
Base class to represents an architected register of any size that is a power of 2 and greater than 0 ...
size_type getNumBits() const
Gets the size of this register's value in bits.
uint32_t group_num_type
Numeric group identifier for register lookup.
group_num_type getGroupNum() const
Gets the group number of this register as specified in its definition.
Field * getField(const std::string &name)
Retrieves a child that is a Register::Field with the given dotted path.
RegisterBase(TreeNode *parent, const Definition &def)
Register constructor.
void write(T val, index_type idx=0)
Write a value into this register.
ident_type getSubsetOf() const
Returns the identity of the compound Register in the same Register set which this register is a subse...
static constexpr ident_type INVALID_ID
Represents an invalid Register ID.
T read(index_type idx=0)
Read a value from this register.
void dmiWrite(T val, index_type idx=0)
Write a value directly to this Register's backing store.
Field * addField(const Field::Definition &fd)
Create a new field in this Register based on the given Field::Definition.
void reset(bool unmasked=true)
Reset this register to its default value.
std::function< bool(RegisterBase *, uint64_t)> register_write_callback_type
Register write callback.
const FieldVector & getFields() const
Const qualified version of getFields.
TreeNode::group_idx_type group_idx_type
TreeNode group index.
NotificationSource< ReadAccess > ReadNotiSrc
Notification type for Register read accesses.
std::string getWriteMaskAsByteString() const
Creats a string representing this register's write-mask as sequence of bytes, separated by spaces,...
Definition::RegDomainT getRegDomain() const
Returns the regdomain for this type.
bool hasReadCB() const
Returns true if register has a read callback; false otherwise.
void poke(T val, index_type idx=0)
Poke a value into this regster.
void addWriteCB(register_write_callback_type callback)
Registers a callback for writing a 32- or 64-bit register value.
std::string getValueAsByteString() const
Creates a string representing this register's value as a sequence of bytes, separated by a spaces,...
std::function< sparta::utils::ValidValue< uint64_t >(RegisterBase *)> register_read_callback_type
Register read callback.
sparta::utils::ValidValue< uint64_t > readWithCheck()
Read a value from this register, possibly via a user-supplied callback.
static constexpr bank_idx_type BANK_IDX_DEFAULT
Default index for bank when no bank is specified. A bank having this index will always exist.
T dmiRead(index_type idx=0) const
Read value directly from the Register's backing store.
PostWriteNotiSrc & getPostWriteNotificationSource()
Returns the post-write notification-source node for this register which can be used to observe writes...
DataView::ident_type ident_type
Identifier to distinguish from other registers in the same RegisterSet.
bool hasWriteCB() const
Returns true if register has a write callback; false otherwise.
bool isInBank(bank_idx_type bank) const
Determines if this register is accessible through a specific bank index (assuming that this bank inde...
virtual ~RegisterBase()
Destructor.
std::vector< Field * > FieldVector
Vector of Register Fields.
ReadNotiSrc & getReadNotificationSource()
Returns the read notification-source node for this register which can be used to observe reads to thi...
size_type getSubsetOffset() const
Returns the byte offset into the compound Register of which this register is a subset.
friend class Field
Allow Fields to access register internals (e.g. dview_)
void pokeUnmasked(T val, index_type idx=0)
Poke a value into this regster without it being affected by the write-mask.
std::string getWriteMaskAsBitString() const
Creats a string representing this register's write-mask as sequence of bits, separated by a space bet...
size_type getNumFields() const
Gets the number of fields within this register.
DataView::offset_type size_type
Size of register and bit or byte offset within register data.
Definition::HintsT getHintFlags() const
Returns the hint flags for this type.
size_type getNumBytes() const
Gets the size of this register's value in bytes.
NotificationSource< PostWriteAccess > PostWriteNotiSrc
Notification type for Register write accesses.
void writeUnmasked(T val, index_type idx=0)
Write a value into this register without it being affected by the write-mask.
std::vector< const char * > AliasVector
Vector of Register Aliases.
uint32_t bank_idx_type
Numeric bank identifier for bank lookup.
static const Definition DEFINITION_END
Entry indicating the end of a sparta::Register::Definition array.
const Definition & getDefinition() const
Gets the definition supplied during the construciton of this Register.
group_idx_type getGroupIdx() const
Gets the group index of this register as specified in its definition.
T getWriteMask(index_type idx=0) const
Get a write mask at the given index of the given size.
const Field * getField(const std::string &name) const
Retrieves a child that is a Register::Field with the given dotted path.
ident_type getID() const
Gets the ID of this register as specified in its definition.
static constexpr group_num_type GROUP_NUM_NONE
Represents no group much like sparta::TreeNode::GROUP_NAME_NONE.
FieldVector & getFields()
Gets the full set of register fields.
void addReadCB(register_read_callback_type callback)
Registers a callback for obtaining a 32- or 64-bit register value.
std::string getGroupName() const
Gets the name of the group to which this register belongs from its definition.
DataView::index_type index_type
Index of read/write access within register.
virtual void onAddingChild_(TreeNode *child) override
React to child registration.
bool isBanked() const
Is this register banked.
bool writeWithCheck(T val)
Write a value to this register, possibly via a user-supplied callback.
uint32_t getSize() const
Get the number of bytes.
void set(const DataT &masked_bits)
Set the given masked_bits in this RegisterBits instance.
const uint8_t * data() const
Get the internal data pointer.
An implementation of a RegisterBase.
RegisterBase::index_type index_type
Index of read/write access within register.
std::string stringize(bool pretty=false) const override
Create a string representation of this node.
T dmiRead(index_type idx=0) const
Read value directly from the Register's backing store.
void dmiWrite(T val, index_type idx=0)
Write a value directly to this Register's backing store.
void writeUnmasked(T val, index_type idx=0)
Write a value into this register without it being affected by the write-mask.
Used to construct and throw a standard C++ exception. Inherits from std::exception.
Node in a composite tree representing a sparta Tree item.
static const group_idx_type GROUP_IDX_NONE
GroupIndex indicating that a node has no group index because it belongs to no group.
std::string getLocation() const override final
static constexpr char GROUP_NAME_NONE[]
Group name indicating that a node belongs to no group.
void addAlias(const std::string &alias)
Add a single alias for this node.
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.
const ConstT getChildAs(const std::string &name, bool must_exist=true) const
Retrieves a child that is castable to T with the given dotted path.
const std::string & getName() const override
Gets the name of this node.
void setExpectedParent_(const TreeNode *parent)
Tracks a node as an expected parent without actually adding this node as a child. This is used almost...
Provides a wrapper around a value to ensure that the value is assigned.
Macros for handling exponential backoff.
std::ostream & operator<<(std::ostream &o, const SimulationInfo &info)
ostream insertion operator for SimulationInfo
bool isPowerOf2(uint64_t x)
Determines if input is 0 or a power of 2.
Describes an architected Register.
const ident_type id
ID. Must be unique within a register set.
const group_num_type group_num
Numeric identifer for the group to which this register belongs. This identifies the group for fast lo...
uint16_t RegDomainT
Register Domain. The flags are not part of sparta but should be defined by the model.
const char * name
String identifier for this register which distinguishes it from its neighbors. Must adhere to TreeNod...
const size_type subset_offset
Offset (in Bytes) into regster of which this is a subset. subset_offset+(this->bytes) must be <= the ...
const char * desc
Description. Must NOT be NULL.
const ident_type subset_of
ID of register of which this is a subset. If INVALID_ID, has no effect.
const unsigned char * initial_value
Initial value of this register.
const char ** aliases
Null-terminated array of of char*s (e.g. {"a", "b", 0}). If there are no aliases, this may be 0.
const size_type bytes
Size of this register in bytes. Non-byte multiples are not supported.
const char * group
String name of group in which this register resides (e.g. gpr). Must NOT be NULL. See sparta::TreeNod...
const bool writable
Writable flag, taken from the register definition.
const group_idx_type group_idx
Index of register within group. See sparta::TreeNode::TreeNode. Internally, a lookup-vector is built ...
const std::vector< bank_idx_type > bank_membership
Vector of bank indexes of banks in which this register is accessible.
const std::vector< Field::Definition > fields
Vector of field definitions. Use like so for empty fields: { name, group_num,..., bytes,...
uint16_t HintsT
Register hint flags. The flags are not part of sparta but should be defined by the model.
Field Definition structure.
size_type high_bit
High bit (inclusive). Must be >= low_bit. (high_bit-low_bit) must be < MAX_FIELD_BITS....
size_type low_bit
Low bit (inclusive)
Definition()=delete
Allow default constructor.
bool read_only
Is this a read-only field.
const char * name
Name - Must ahere to TreeNode::validateName. Must not be NULL.
Definition(const char *_name, const char *_desc, size_type _low_bit, size_type _high_bit)
Limited constructor for backward compatibility.
const char * desc
Description. Must NOT be NULL.
Structure containing data for a Register post-write notification.
const RegisterBase *const reg
Register on which the write access took place.
const DataView *const prior
Value of reg prior to this write.
Structure containing data for a Register pre- or post-read notification.
const DataView *const value
Value just read from reg. This value can also be retrieved through reg.
const RegisterBase *const reg
Register on which the read access took place.