14#include "sparta/functional/DataView.hpp"
15#include "sparta/functional/RegisterBits.hpp"
16#include "sparta/utils/Utils.hpp"
17#include "sparta/log/NotificationSource.hpp"
137 RegisterBits computeFieldMask_(uint32_t start, uint32_t end, uint32_t reg_size)
139 const auto num_ones = start - end + 1;
144 const uint64_t masked_bits = std::numeric_limits<uint64_t>::max() &
145 (std::numeric_limits<uint64_t>::max() >> ((
sizeof(uint64_t) * CHAR_BIT) - num_ones));
146 mask.
set(masked_bits);
221 field_mask_(computeFieldMask_(def.high_bit, def.low_bit, reg_.
getNumBytes())),
222 not_field_mask_(~field_mask_)
226 sparta_assert(def_.
name != 0,
"Register::Field::Definition::name cannot be empty");
231 <<
") less than a low bit (" << def_.
low_bit <<
")";
237 <<
") greater than or equal to the number of bits in the register ("
243 <<
") greater than or equal to the number of bits in the register ("
250 <<
"Problem with field \"" <<
getLocation() <<
"\"";
289 write_(newRegisterValue_(t));
301 poke_(newRegisterValue_(t));
309 pokeUnmasked_(newRegisterValue_(t));
357 virtual std::string
stringize(
bool pretty=
false)
const override{
359 std::stringstream ss;
362 ss <<
" bits LE:0x" << std::hex <<
peek();
374 reg_.
read(reg_bits.data(), reg_size_, 0);
381 reg_.peek(reg_bits.data(), reg_size_, 0);
385 void write_(
const RegisterBits &value)
387 reg_.
write(value.data(), value.getSize(), 0);
390 void poke_(
const RegisterBits &value)
392 reg_.
poke(value.data(), value.getSize(), 0);
395 void pokeUnmasked_(
const RegisterBits &value)
400 RegisterBits newRegisterValue_(
access_type value)
const
402 const auto old_register_value = peekBitArray_();
404 RegisterBits field_value_to_be_written_shifted(std::max((
size_t)reg_size_,
sizeof(
access_type)), value);
405 field_value_to_be_written_shifted <<=
getLowBit();
409 sparta_assert((field_value_to_be_written_shifted & not_field_mask_).none(),
410 "Value of " << value <<
" too large for bit field "
413 return (old_register_value & not_field_mask_) | field_value_to_be_written_shifted;
424 const Definition &def_;
434 const RegisterBits field_mask_;
439 const RegisterBits not_field_mask_;
489 :
reg(_reg),
prior(_prior_dview),
final(_final_dview)
610 const std::vector<Field::Definition>
fields;
723 NULL_TO_EMPTY_STR(def.name),
724 NULL_TO_EMPTY_STR(def.group),
726 NULL_TO_EMPTY_STR(def.desc),
729 bits_(def.bytes * 8),
730 mask_(computeWriteMask_(&def_)),
731 post_write_noti_(this,
733 "Notification immediately after the register has been written",
735 post_read_noti_(this,
737 "Notification immediately after the register has been read",
740 if(parent !=
nullptr){
744 sparta_assert(def.
name != 0,
"Cannot have a null name in a register definition");
749 <<
" but had group name \"\". A group name is required if a group number is specified.";
754 <<
getLocation() <<
"\" which had group number GROUP_NUM_NONE"
755 <<
" but had group name \"" << def.
group
756 <<
"\". A group number is required if a group name is specified.\"" <<
GROUP_NAME_NONE <<
"\"";
760 static_assert(std::is_unsigned<
decltype(def.
bytes)>::value ==
true);
763 <<
getName() <<
"\" size in bytes must be a power of 2 larger than 0, is "
768 for(
auto & fdp : def_.
fields){
773 const char*
const * ap = def_.
aliases;
782 if(parent !=
nullptr){
794 for(
Field* f : owned_fields_){
831 owned_fields_.push_back(
new Field(*
this, fd));
832 return owned_fields_.back();
980 template <
typename T>
984 read(&tmp,
sizeof(tmp), idx *
sizeof(tmp));
994 return read_with_check_cb_(
this);
996 return read<uint32_t>();
1000 "read callback only support for 4- and 8-byte registers");
1001 return read<uint64_t>();
1010 template <
typename T>
1013 if (!isWritable())
return;
1014 write(&val,
sizeof(val), idx *
sizeof(val));
1020 template <
typename T>
1023 if (!isWritable())
return false;
1025 static_assert((
sizeof(T)==4) || (
sizeof(T)==8),
1026 "write callback only support for 4- and 8-byte registers");
1027 return write_with_check_cb_(
this, val);
1038 template <
typename T>
1041 if (!isWritable())
return;
1045 template <
typename T>
1049 peek(&tmp,
sizeof(tmp), idx *
sizeof(tmp));
1057 template <
typename T>
1060 if (!isWritable())
return;
1061 poke(&val,
sizeof(val), idx *
sizeof(val));
1069 template <
typename T>
1072 if (!isWritable())
return;
1079 template <
typename T>
1083 dmiRead_(&res,
sizeof(res),
sizeof(res) * idx);
1091 template <
typename T>
1094 if (!isWritable())
return;
1095 dmiWrite_(&val,
sizeof(val),
sizeof(val) * idx);
1105 template <
typename T>
1109 return *(
reinterpret_cast<const T*
>(mask_.
data()) + idx);
1115 bool isWritable()
const
1138 std::vector<uint8_t> value(size);
1139 peek(value.data(), size, 0);
1140 return utils::bin_to_hexstr(value.data(), size);
1153 return utils::bin_to_hexstr(
1154 reinterpret_cast<const uint8_t *
>(mask_.
data()), mask_.
getSize());
1168 return utils::bin_to_bitstr(
1169 reinterpret_cast<const uint8_t *
>(mask_.
data()), mask_.
getSize());
1184 return getChildAs<Field *>(name);
1196 return getChildAs<Field *>(name);
1203 void read(
void *buf,
size_t size,
size_t offset)
1206 read_(buf, size, offset);
1209 void peek(
void *buf,
size_t size,
size_t offset)
const
1212 peek_(buf, size, offset);
1215 void write(
const void *buf,
size_t size,
size_t offset)
1217 if (!isWritable())
return;
1219 RegisterBits val(
reinterpret_cast<const uint8_t *
>(buf), size);
1220 RegisterBits mask = mask_ >> 8 * offset;
1221 RegisterBits old = (peekRegisterBits_(size, offset) & ~mask) | (val & mask);
1222 write_(old.data(), size, offset);
1225 void writeUnmasked(
const void *buf,
size_t size,
size_t offset)
1227 if (!isWritable())
return;
1229 write_(buf, size, offset);
1232 void poke(
const void *buf,
size_t size,
size_t offset)
1234 if (!isWritable())
return;
1236 RegisterBits val(
reinterpret_cast<const uint8_t *
>(buf), size);
1237 RegisterBits mask = mask_ >> 8 * offset;
1238 RegisterBits old = (peekRegisterBits_(size, offset) & ~mask) | (val & mask);
1239 poke_(old.data(), size, offset);
1242 void pokeUnmasked(
const void *buf,
size_t size,
size_t offset)
1244 if (!isWritable())
return;
1246 poke_(buf, size, offset);
1265 return post_write_noti_;
1281 return post_read_noti_;
1289 read_with_check_cb_ = callback;
1297 return read_with_check_cb_ !=
nullptr;
1305 write_with_check_cb_ = callback;
1313 return write_with_check_cb_ !=
nullptr;
1331 fields_.push_back(fld);
1335 virtual void read_(
void *buf,
size_t size,
size_t offset = 0) = 0;
1337 virtual void peek_(
void *buf,
size_t size,
size_t offset = 0)
const = 0;
1339 virtual void write_(
const void *buf,
size_t size,
size_t offset = 0) = 0;
1341 virtual void poke_(
const void *buf,
size_t size,
size_t offset = 0) = 0;
1343 virtual void dmiRead_(
void *buf,
size_t size,
size_t offset = 0)
const
1345 (void)buf; (void)size; (void)offset;
1349 virtual void dmiWrite_(
const void *buf,
size_t size,
size_t offset = 0)
1351 (void)buf; (void)size; (void)offset;
1356 RegisterBits computeWriteMask_(
const Definition *def)
const
1359 throw SpartaException(
"Register \"")
1360 <<
getName() <<
"\" size in bytes must be a power of 2 larger than 0, is "
1364 const auto mask_size = def->bytes;
1365 RegisterBits write_mask(mask_size);
1366 RegisterBits partial_mask(mask_size);
1367 partial_mask.fill(0xff);
1369 for (
auto &fdp : def->fields) {
1370 if (fdp.read_only) {
1371 const uint64_t field_size = fdp.high_bit - fdp.low_bit + 1;
1372 const uint64_t shift_down = 8 * mask_size - field_size;
1373 const uint64_t shift_up = fdp.low_bit;
1375 write_mask |= ((partial_mask >> shift_down) << shift_up);
1382 RegisterBits peekRegisterBits_(
size_t size,
size_t offset=0)
const
1384 RegisterBits bits(size);
1385 peek_(bits.data(), size, offset);
1392 const Definition def_;
1413 const RegisterBits mask_;
1432inline bool operator==(
const RegisterBase::Definition &a,
1433 const RegisterBase::Definition &b)
1438 if (!utils::strcmp_with_null(a.name, b.name)) {
1441 if (a.group_num != b.group_num) {
1444 if (!utils::strcmp_with_null(a.group, b.group)) {
1447 if (a.group_idx != b.group_idx) {
1450 if (!utils::strcmp_with_null(a.desc, b.desc)) {
1453 if (a.bytes != b.bytes) {
1459 if (a.bank_membership != b.bank_membership) {
1463 auto a_aliases = a.aliases;
1464 auto b_aliases = b.aliases;
1465 if (a_aliases !=
nullptr && b_aliases !=
nullptr) {
1466 for (; *a_aliases != 0 || *b_aliases != 0; ++a_aliases, ++b_aliases) {
1467 if (!utils::strcmp_with_null(*a_aliases, *b_aliases)) {
1471 }
else if (!(a_aliases ==
nullptr && b_aliases ==
nullptr)) {
1475 if (a.subset_of != b.subset_of) {
1478 if (!utils::strcmp_with_null((
const char *)a.initial_value, (
const char *)b.initial_value)) {
1481 if (a.hints != b.hints) {
1484 if (a.regdomain != b.regdomain) {
1491inline bool operator!=(
const RegisterBase::Definition &a,
1492 const RegisterBase::Definition &b)
1512 post_write_noti_data_(
this, &prior_val_dview_, &dview_),
1513 post_read_noti_data_(
this, &dview_)
1521 std::stringstream ss;
1542 template <
typename T>
1546 dmiReadImpl_(&res,
sizeof(res),
sizeof(res) * idx);
1556 template <
typename T>
1559 if (!isWritable())
return;
1560 dmiWriteImpl_(&val,
sizeof(val),
sizeof(val) * idx);
1569 template <
typename T>
1572 if (!isWritable())
return;
1573 dmiWriteImpl_(&val,
sizeof(T), idx);
1580 void onBindTreeEarly_()
override
1587 void read_(
void *buf,
size_t size,
size_t offset=0) override final
1591 peek_(buf, size, offset);
1593 post_read_noti.postNotification(post_read_noti_data_);
1597 void peek_(
void *buf,
size_t size,
size_t offset=0) const override final
1600 dview_.
getOffset() + offset, size,
static_cast<uint8_t *
>(buf));
1603 void dmiRead_(
void *buf,
size_t size,
size_t offset = 0) const override final
1605 dmiReadImpl_(buf, size, offset);
1608 void write_(
const void *buf,
size_t size,
size_t offset=0) override final
1610 if (!isWritable())
return;
1614 prior_val_dview_ = dview_;
1615 poke_(buf, size, offset);
1616 post_write_noti.postNotification(post_write_noti_data_);
1618 poke_(buf, size, offset);
1622 void poke_(
const void *buf,
size_t size,
size_t offset=0) override final
1624 if (!isWritable())
return;
1626 dview_.
getOffset() + offset, size,
static_cast<const uint8_t *
>(buf));
1629 void dmiWrite_(
const void *buf,
size_t size,
size_t offset = 0) override final
1631 if (!isWritable())
return;
1632 dmiWriteImpl_(buf, size, offset);
1635 inline void dmiReadImpl_(
void *buf,
size_t size,
size_t offset = 0)
const
1637 memcpy(buf, raw_data_ptr_ + offset, size);
1640 inline void dmiWriteImpl_(
const void *buf,
size_t size,
size_t offset = 0)
1642 if (!isWritable())
return;
1643 memcpy(raw_data_ptr_ + offset, buf, size);
1656 DataView prior_val_dview_;
1671 uint8_t *raw_data_ptr_ =
nullptr;
1712#define SPARTA_REGISTER_BODY \
1713 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.
uint32_t index_type
Type used for specifying index into this DataView during a read or write.
ArchData::Line * getLine() const
Get already-placed line.
ArchDataSegment::offset_type offset_type
Represents offset into ArchData.
offset_type getOffset() const
ArchData * getArchData() const
ArchDataSegment::ident_type ident_type
DataView identifiers (distinguishes views in the same ArchData)
static const std::string DATAVIEW_UNPLACED_STR
String to show instead of a value when representing an unplaced dataview.
A TreeNode that generates a specific type of notification which propagates up a tree of TreeNodes (us...
PostWriteAccess data_type
Type of notification data generated by this instance.
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.
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.
uint64_t access_type
Type used for bitfield access.
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.
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.
DataView::ident_type ident_type
Identifier to distinguish from other registers in the same RegisterSet.
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.
uint32_t bank_idx_type
Numeric bank identifier for bank lookup.
NotificationSource< PostWriteAccess > PostWriteNotiSrc
Notification type for Register write accesses.
std::function< bool(RegisterBase *, uint64_t)> register_write_callback_type
Register write callback.
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::vector< const char * > AliasVector
Vector of Register Aliases.
const FieldVector & getFields() const
Const qualified version of getFields.
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,...
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.
TreeNode::group_idx_type group_idx_type
TreeNode group index.
PostWriteNotiSrc & getPostWriteNotificationSource()
Returns the post-write notification-source node for this register which can be used to observe writes...
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.
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.
std::vector< Field * > FieldVector
Vector of Register Fields.
DataView::offset_type size_type
Size of register and bit or byte offset within register data.
void pokeUnmasked(T val, index_type idx=0)
Poke a value into this regster without it being affected by the write-mask.
uint32_t group_num_type
Numeric group identifier for register lookup.
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.
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.
void writeUnmasked(T val, index_type idx=0)
Write a value into this register without it being affected by the write-mask.
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.
std::function< sparta::utils::ValidValue< uint64_t >(RegisterBase *)> register_read_callback_type
Register read callback.
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.
NotificationSource< ReadAccess > ReadNotiSrc
Notification type for Register read accesses.
virtual void onAddingChild_(TreeNode *child) override
React to child registration.
bool isBanked() const
Is this register banked.
DataView::index_type index_type
Index of read/write access within register.
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.
std::string stringize(bool pretty=false) const override
Create a string representation of this node.
RegisterBase::index_type index_type
Index of read/write access within register.
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 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...
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.
uint16_t HintsT
Register hint flags. The flags are not part of sparta but should be defined by the model.
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...
uint16_t RegDomainT
Register Domain. The flags are not part of sparta but should be defined by the model.
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,...
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.