The Sparta Modeling Framework
Loading...
Searching...
No Matches
Register.hpp
1// <Register> -*- C++ -*-
2
3#pragma once
4
5#include <iostream>
6#include <ios>
7#include <iomanip>
8#include <sstream>
9#include <math.h>
10#include <memory>
11#include <climits>
12
14#include "sparta/functional/DataView.hpp"
15#include "sparta/functional/RegisterBits.hpp"
16#include "sparta/utils/Utils.hpp"
17#include "sparta/log/NotificationSource.hpp"
22
23namespace sparta
24{
25
62class RegisterBase : public TreeNode
63{
64
65public:
66 class Field;
67
73
78
83
87 typedef uint32_t group_num_type;
88
93
98 typedef uint32_t bank_idx_type;
99
103 typedef std::vector<const char*> AliasVector;
104
108 typedef std::vector<Field*> FieldVector;
109
113 typedef std::function<sparta::utils::ValidValue<uint64_t>(RegisterBase*)> register_read_callback_type;
114
118 typedef std::function<bool(RegisterBase*, uint64_t)> register_write_callback_type;
119
122
127 static constexpr bank_idx_type BANK_IDX_DEFAULT = 0;
128
135 class Field : public TreeNode
136 {
137 RegisterBits computeFieldMask_(uint32_t start, uint32_t end, uint32_t reg_size)
138 {
139 const auto num_ones = start - end + 1;
140 RegisterBits mask(reg_size);
141 // For 31-0:
142
143 // max() & (max() >> ((8 * 8) - 31))
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);
147 mask <<= end;
148 return mask;
149 }
150
151 public:
152
156 typedef uint64_t access_type;
157
161 static const size_type MAX_FIELD_BITS = sizeof(access_type) * 8;
162
168 {
172 Definition() = delete;
173
178 Definition(const char* _name,
179 const char* _desc,
180 size_type _low_bit,
181 size_type _high_bit) :
182 name(_name),
183 desc(_desc),
184 low_bit(_low_bit),
185 high_bit(_high_bit),
186 read_only(false)
187 {;}
188
189 Definition(const char* _name,
190 const char* _desc,
191 size_type _low_bit,
192 size_type _high_bit,
193 bool _read_only) :
194 name(_name),
195 desc(_desc),
196 low_bit(_low_bit),
197 high_bit(_high_bit),
198 read_only(_read_only)
199 {;}
200
201 const char* name;
202 const char* desc;
206 };
207
215 Field(RegisterBase &reg, const Definition &def) :
216 TreeNode(NULL_TO_EMPTY_STR(def.name), TreeNode::GROUP_NAME_NONE,
217 TreeNode::GROUP_IDX_NONE, NULL_TO_EMPTY_STR(def.desc)),
218 reg_(reg),
219 def_(def),
220 reg_size_(reg_.getNumBytes()),
221 field_mask_(computeFieldMask_(def.high_bit, def.low_bit, reg_.getNumBytes())),
222 not_field_mask_(~field_mask_)
223 {
224 setExpectedParent_(&reg);
225
226 sparta_assert(def_.name != 0, "Register::Field::Definition::name cannot be empty");
227
228 if(def_.high_bit < def_.low_bit){
229 throw SpartaException("Register Field ")
230 << getLocation() << " definition contains high bit (" << def_.high_bit
231 << ") less than a low bit (" << def_.low_bit << ")";
232 }
233
234 if(def_.low_bit >= reg.getNumBits()){
235 throw SpartaException("Register Field ")
236 << getLocation() << " definition contains a low bit (" << def_.low_bit
237 << ") greater than or equal to the number of bits in the register ("
238 << reg.getNumBits() << ")";
239 }
240 if(def_.high_bit >= reg.getNumBits()){
241 throw SpartaException("Register Field ")
242 << getLocation() << " definition contains a high bit (" << def_.high_bit
243 << ") greater than or equal to the number of bits in the register ("
244 << reg.getNumBits() << ")";
245 }
246
248 throw SpartaException("Cannot currently support more than ")
249 << (size_type)MAX_FIELD_BITS << "bit-wide fields. "
250 << "Problem with field \"" << getLocation() << "\"";
251 }
252
253 // Add self as child after successful initialization
254 reg.addChild(this);
255 }
256
260
267 {
268 return ((readBitArray_() & field_mask_) >> getLowBit()).dataAs<access_type>();
269 }
270
277 {
278 return ((peekBitArray_() & field_mask_) >> getLowBit()).dataAs<access_type>();
279 }
280
288 {
289 write_(newRegisterValue_(t));
290 }
291
300 {
301 poke_(newRegisterValue_(t));
302 }
303
308 {
309 pokeUnmasked_(newRegisterValue_(t));
310 }
311
314
318
324 size_type getLowBit() const { return def_.low_bit; }
325
331 size_type getHighBit() const { return def_.high_bit; }
332
336 bool isReadOnly() const { return def_.read_only; }
337
342 {
343 return getHighBit() - getLowBit() + 1;
344 }
345
349 const Definition& getDefinition() const {
350 return def_;
351 }
352
355
356 // Override from TreeNode
357 virtual std::string stringize(bool pretty=false) const override{
358 (void) pretty;
359 std::stringstream ss;
360 ss << '<' << getLocation() << " [" << def_.low_bit << "-"
361 << def_.high_bit << "] " << getNumBits();
362 ss << " bits LE:0x" << std::hex << peek();
363 if(def_.read_only){
364 ss << " READ-ONLY";
365 }
366 ss << '>';
367 return ss.str();
368 }
369
370 private:
371 RegisterBits readBitArray_() const
372 {
373 RegisterBits reg_bits(reg_size_);
374 reg_.read(reg_bits.data(), reg_size_, 0);
375 return reg_bits;
376 }
377
378 RegisterBits peekBitArray_() const
379 {
380 RegisterBits reg_bits(reg_size_);
381 reg_.peek(reg_bits.data(), reg_size_, 0);
382 return reg_bits;
383 }
384
385 void write_(const RegisterBits &value)
386 {
387 reg_.write(value.data(), value.getSize(), 0);
388 }
389
390 void poke_(const RegisterBits &value)
391 {
392 reg_.poke(value.data(), value.getSize(), 0);
393 }
394
395 void pokeUnmasked_(const RegisterBits &value)
396 {
397 reg_.pokeUnmasked(value.data(), value.getSize(), 0);
398 }
399
400 RegisterBits newRegisterValue_(access_type value) const
401 {
402 const auto old_register_value = peekBitArray_();
403
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();
406
407 // Check to see if the number of bits being written to the
408 // field is larger than the field itself.
409 sparta_assert((field_value_to_be_written_shifted & not_field_mask_).none(),
410 "Value of " << value << " too large for bit field "
411 << getLocation() << " of size " << getNumBits());
412
413 return (old_register_value & not_field_mask_) | field_value_to_be_written_shifted;
414 }
415
419 RegisterBase &reg_;
420
424 const Definition &def_;
425
429 const RegisterBase::size_type reg_size_ = 0;
430
434 const RegisterBits field_mask_;
435
439 const RegisterBits not_field_mask_;
440
441 }; // class Field
442
451 {
452 ReadAccess() = delete;
453
454 ReadAccess(const RegisterBase *_reg, const DataView *_value_dview)
455 : reg(_reg), value(_value_dview)
456 {
457 }
458
462 const RegisterBase *const reg;
463
468 const DataView *const value;
469 };
470
475
483 {
484 PostWriteAccess() = delete;
485
486 PostWriteAccess(const RegisterBase *_reg,
487 const DataView *_prior_dview,
488 const DataView *_final_dview)
489 : reg(_reg), prior(_prior_dview), final(_final_dview)
490 {
491 }
492
496 const RegisterBase *const reg;
497
501 const DataView *const prior;
502
508 const DataView *const final;
509 };
510
515
548 {
553
559 const char* name;
560
574
583 const char* group;
584
592
596 const char* desc;
597
603
610 const std::vector<Field::Definition> fields;
611
638 const std::vector<bank_idx_type> bank_membership;
639
644 const char** aliases;
645
651
659
663 const unsigned char* initial_value;
664
669 typedef uint16_t HintsT;
670 const HintsT hints;
671
676 typedef uint16_t RegDomainT;
677 const RegDomainT regdomain;
678 };
679
682
685
688
690 friend class Field;
691
695
716 RegisterBase(TreeNode *parent, const Definition & def)
717 : TreeNode(nullptr,
718 NULL_TO_EMPTY_STR(def.name),
719 NULL_TO_EMPTY_STR(def.group),
720 def.group_idx,
721 NULL_TO_EMPTY_STR(def.desc),
722 false),
723 def_(def),
724 bits_(def.bytes * 8),
725 mask_(computeWriteMask_(&def_)),
726 post_write_noti_(this,
727 "post_write",
728 "Notification immediately after the register has been written",
729 "post_write"),
730 post_read_noti_(this,
731 "post_read",
732 "Notification immediately after the register has been read",
733 "post_read")
734 {
735 if(parent != nullptr){
736 setExpectedParent_(parent);
737 }
738
739 sparta_assert(def.name != 0, "Cannot have a null name in a register definition");
740
741 if(!strcmp(def_.group, GROUP_NAME_NONE) && (def.group_num != GROUP_NUM_NONE)){
742 throw SpartaException("Attempted to add register \"")
743 << getLocation() << "\" which had group number " << def.group_num
744 << " but had group name \"\". A group name is required if a group number is specified.";
745 }
746
747 if(strcmp(def.group, GROUP_NAME_NONE) && (def.group_num == GROUP_NUM_NONE)){
748 throw SpartaException("Attempted to add register \"")
749 << getLocation() << "\" which had group number GROUP_NUM_NONE"
750 << " but had group name \"" << def.group
751 << "\". A group number is required if a group name is specified.\"" << GROUP_NAME_NONE << "\"";
752 }
753
754 // Ensure byte-size is valid
755 static_assert(std::is_unsigned<decltype(def.bytes)>::value == true);
756 if(!isPowerOf2(def.bytes) || def.bytes == 0){
757 throw SpartaException("Register \"")
758 << getName() << "\" size in bytes must be a power of 2 larger than 0, is "
759 << def.bytes;
760 }
761
762 // Add all fields
763 for(auto & fdp : def_.fields){
764 addField(fdp);
765 }
766
767 // Add all aliases
768 const char* const * ap = def_.aliases;
769 if(ap != 0){
770 while(*ap != 0){
771 addAlias(*ap); // From sparta::TreeNode
772 ++ap;
773 }
774 }
775
776 // Must add child only after assigning all aliases
777 if(parent != nullptr){
778 parent->addChild(this);
779 }
780 }
781
788 {
789 for(Field* f : owned_fields_){
790 delete f;
791 }
792 }
793
798 void reset(bool unmasked=true) {
799 // Poke the whole value, one-byte at a time
800 for(size_type i=0; i<def_.bytes; i++){
801 if(unmasked){
802 pokeUnmasked(def_.initial_value[i], i);
803 }else{
804 poke(def_.initial_value[i], i);
805 }
806 }
807 }
808
826 owned_fields_.push_back(new Field(*this, fd));
827 return owned_fields_.back();
828 }
829
832
836
840 ident_type getID() const { return def_.id; }
841
846 group_num_type getGroupNum() const { return def_.group_num; }
847
853 std::string getGroupName() const {
854 // Return group. Guaranteed not to be null by Register::Register
855 return def_.group;
856 }
857
862 group_idx_type getGroupIdx() const { return def_.group_idx; }
863
867 size_type getNumBytes() const { return def_.bytes; }
868
872 size_type getNumBits() const { return bits_; }
873
877 size_type getNumFields() const { return (size_type)fields_.size(); }
878
894 bool isInBank(bank_idx_type bank) const {
895 if(isBanked() == false){
896 return true;
897 }
898
899 auto itr = std::find(def_.bank_membership.begin(), def_.bank_membership.end(), bank);
900 return itr != def_.bank_membership.end();
901 }
902
909 bool isBanked() const {
910 return def_.bank_membership.size() != 0;
911 }
912
916 FieldVector& getFields() { return fields_; }
917
921 const FieldVector& getFields() const { return fields_; }
922
930 ident_type getSubsetOf() const { return def_.subset_of; }
931
941 size_type getSubsetOffset() const { return def_.subset_offset; }
942
947 Definition::HintsT getHintFlags() const { return def_.hints; }
948
953 Definition::RegDomainT getRegDomain() const { return def_.regdomain; }
954
961 const Definition& getDefinition() const {
962 return def_;
963 }
964
967
971
975 template <typename T>
977 {
978 T tmp;
979 read(&tmp, sizeof(tmp), idx * sizeof(tmp));
980 return tmp;
981 }
982
987 {
988 if (hasReadCB()) {
989 return read_with_check_cb_(this);
990 } else if (getNumBytes()==4) {
991 return read<uint32_t>();
992 }
993
995 "read callback only support for 4- and 8-byte registers");
996 return read<uint64_t>();
997 }
998
1005 template <typename T>
1006 void write(T val, index_type idx=0)
1007 {
1008 write(&val, sizeof(val), idx * sizeof(val));
1009 }
1010
1014 template <typename T>
1015 bool writeWithCheck(T val)
1016 {
1017 if (hasWriteCB()) {
1018 static_assert((sizeof(T)==4) || (sizeof(T)==8),
1019 "write callback only support for 4- and 8-byte registers");
1020 return write_with_check_cb_(this, val);
1021 }
1022 write<T>(val);
1023 return true;
1024 }
1025
1031 template <typename T>
1032 void writeUnmasked(T val, index_type idx=0)
1033 {
1034 writeUnmasked(&val, sizeof(val), idx * sizeof(val));
1035 }
1036
1037 template <typename T>
1038 T peek(index_type idx=0) const
1039 {
1040 T tmp;
1041 peek(&tmp, sizeof(tmp), idx * sizeof(tmp));
1042 return tmp;
1043 }
1044
1049 template <typename T>
1050 void poke(T val, index_type idx=0)
1051 {
1052 poke(&val, sizeof(val), idx * sizeof(val));
1053 }
1054
1060 template <typename T>
1061 void pokeUnmasked(T val, index_type idx=0)
1062 {
1063 pokeUnmasked(&val, sizeof(val), idx * sizeof(val));
1064 }
1065
1069 template <typename T>
1070 T dmiRead(index_type idx = 0) const
1071 {
1072 T res;
1073 dmiRead_(&res, sizeof(res), sizeof(res) * idx);
1074 return res;
1075 }
1076
1081 template <typename T>
1082 void dmiWrite(T val, index_type idx = 0)
1083 {
1084 dmiWrite_(&val, sizeof(val), sizeof(val) * idx);
1085 }
1086
1094 template <typename T>
1096 {
1097 sparta_assert((idx + 1) * sizeof(T) <= mask_.getSize());
1098 return *(reinterpret_cast<const T*>(mask_.data()) + idx);
1099 }
1100
1103
1107
1116 std::string getValueAsByteString() const
1117 {
1118 const auto size = getNumBytes();
1119 std::vector<uint8_t> value(size);
1120 peek(value.data(), size, 0);
1121 return utils::bin_to_hexstr(value.data(), size);
1122 }
1123
1132 std::string getWriteMaskAsByteString() const
1133 {
1134 return utils::bin_to_hexstr(
1135 reinterpret_cast<const uint8_t *>(mask_.data()), mask_.getSize());
1136 }
1137
1147 std::string getWriteMaskAsBitString() const
1148 {
1149 return utils::bin_to_bitstr(
1150 reinterpret_cast<const uint8_t *>(mask_.data()), mask_.getSize());
1151 }
1152
1155
1163 Field *getField(const std::string &name)
1164 {
1165 return getChildAs<Field *>(name);
1166 }
1167
1175 const Field *getField(const std::string &name) const
1176 {
1177 return getChildAs<Field *>(name);
1178 }
1179
1183
1184 void read(void *buf, size_t size, size_t offset)
1185 {
1186 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
1187 read_(buf, size, offset);
1188 }
1189
1190 void peek(void *buf, size_t size, size_t offset) const
1191 {
1192 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
1193 peek_(buf, size, offset);
1194 }
1195
1196 void write(const void *buf, size_t size, size_t offset)
1197 {
1198 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
1199 RegisterBits val(reinterpret_cast<const uint8_t *>(buf), size);
1200 RegisterBits mask = mask_ >> 8 * offset;
1201 RegisterBits old = (peekRegisterBits_(size, offset) & ~mask) | (val & mask);
1202 write_(old.data(), size, offset);
1203 }
1204
1205 void writeUnmasked(const void *buf, size_t size, size_t offset)
1206 {
1207 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
1208 write_(buf, size, offset);
1209 }
1210
1211 void poke(const void *buf, size_t size, size_t offset)
1212 {
1213 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
1214 RegisterBits val(reinterpret_cast<const uint8_t *>(buf), size);
1215 RegisterBits mask = mask_ >> 8 * offset;
1216 RegisterBits old = (peekRegisterBits_(size, offset) & ~mask) | (val & mask);
1217 poke_(old.data(), size, offset);
1218 }
1219
1220 void pokeUnmasked(const void *buf, size_t size, size_t offset)
1221 {
1222 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
1223 poke_(buf, size, offset);
1224 }
1225
1228
1241 {
1242 return post_write_noti_;
1243 }
1244
1257 {
1258 return post_read_noti_;
1259 }
1260
1265 {
1266 read_with_check_cb_ = callback;
1267 }
1268
1272 bool hasReadCB() const
1273 {
1274 return read_with_check_cb_ != nullptr;
1275 }
1276
1281 {
1282 write_with_check_cb_ = callback;
1283 }
1284
1288 bool hasWriteCB() const
1289 {
1290 return write_with_check_cb_ != nullptr;
1291 }
1292
1293protected:
1294
1304 virtual void onAddingChild_(TreeNode* child) override {
1305 Field* fld = dynamic_cast<Field*>(child);
1306 if(nullptr != fld){
1307 // Add Field to fields_ list for tracking.
1308 fields_.push_back(fld);
1309 }
1310 }
1311
1312 virtual void read_(void *buf, size_t size, size_t offset = 0) = 0;
1313
1314 virtual void peek_(void *buf, size_t size, size_t offset = 0) const = 0;
1315
1316 virtual void write_(const void *buf, size_t size, size_t offset = 0) = 0;
1317
1318 virtual void poke_(const void *buf, size_t size, size_t offset = 0) = 0;
1319
1320 virtual void dmiRead_(void *buf, size_t size, size_t offset = 0) const
1321 {
1322 (void)buf; (void)size; (void)offset;
1323 sparta_assert(!"Register DMI not supported");
1324 }
1325
1326 virtual void dmiWrite_(const void *buf, size_t size, size_t offset = 0)
1327 {
1328 (void)buf; (void)size; (void)offset;
1329 sparta_assert(!"Register DMI not supported");
1330 }
1331
1332private:
1333 RegisterBits computeWriteMask_(const Definition *def) const
1334 {
1335 if(!isPowerOf2(def->bytes)) {
1336 throw SpartaException("Register \"")
1337 << getName() << "\" size in bytes must be a power of 2 larger than 0, is "
1338 << def->bytes;
1339 }
1340
1341 const auto mask_size = def->bytes;
1342 RegisterBits write_mask(mask_size);
1343 RegisterBits partial_mask(mask_size);
1344 partial_mask.fill(0xff);
1345
1346 for (auto &fdp : def->fields) {
1347 if (fdp.read_only) {
1348 const uint64_t field_size = fdp.high_bit - fdp.low_bit + 1;
1349 const uint64_t shift_down = 8 * mask_size - field_size;
1350 const uint64_t shift_up = fdp.low_bit;
1351
1352 write_mask |= ((partial_mask >> shift_down) << shift_up);
1353 }
1354
1355 }
1356
1357 return ~write_mask;
1358 }
1359
1360 RegisterBits peekRegisterBits_(size_t size, size_t offset=0) const
1361 {
1362 RegisterBits bits(size);
1363 peek_(bits.data(), size, offset);
1364 return bits;
1365 }
1366
1370 const Definition def_;
1371
1376 FieldVector owned_fields_;
1377
1381 FieldVector fields_;
1382
1386 const size_type bits_;
1387
1391 const RegisterBits mask_;
1392
1396 PostWriteNotiSrc post_write_noti_;
1397
1401 ReadNotiSrc post_read_noti_;
1402
1406 register_read_callback_type read_with_check_cb_ {nullptr};
1407 register_write_callback_type write_with_check_cb_ {nullptr};
1408}; // class RegisterBase
1409
1410inline bool operator==(const RegisterBase::Definition &a,
1411 const RegisterBase::Definition &b)
1412{
1413 if (a.id != b.id) {
1414 return false;
1415 }
1416 if (!utils::strcmp_with_null(a.name, b.name)) {
1417 return false;
1418 }
1419 if (a.group_num != b.group_num) {
1420 return false;
1421 }
1422 if (!utils::strcmp_with_null(a.group, b.group)) {
1423 return false;
1424 }
1425 if (a.group_idx != b.group_idx) {
1426 return false;
1427 }
1428 if (!utils::strcmp_with_null(a.desc, b.desc)) {
1429 return false;
1430 }
1431 if (a.bytes != b.bytes) {
1432 return false;
1433 }
1434
1435 /* TODO: Compare fields. This require a == operator for Field::Definition */
1436
1437 if (a.bank_membership != b.bank_membership) {
1438 return false;
1439 }
1440
1441 auto a_aliases = a.aliases;
1442 auto b_aliases = b.aliases;
1443 if (a_aliases != nullptr && b_aliases != nullptr) {
1444 for (; *a_aliases != 0 || *b_aliases != 0; ++a_aliases, ++b_aliases) {
1445 if (!utils::strcmp_with_null(*a_aliases, *b_aliases)) {
1446 return false;
1447 }
1448 }
1449 } else if (!(a_aliases == nullptr && b_aliases == nullptr)) {
1450 return false;
1451 }
1452
1453 if (a.subset_of != b.subset_of) {
1454 return false;
1455 }
1456 if (!utils::strcmp_with_null((const char *)a.initial_value, (const char *)b.initial_value)) {
1457 return false;
1458 }
1459 if (a.hints != b.hints) {
1460 return false;
1461 }
1462 if (a.regdomain != b.regdomain) {
1463 return false;
1464 }
1465
1466 return true;
1467}
1468
1469inline bool operator!=(const RegisterBase::Definition &a,
1470 const RegisterBase::Definition &b)
1471{
1472 return !(a == b);
1473}
1474
1484{
1485public:
1486 Register(TreeNode *parent, const Definition def, ArchData *adata) :
1487 RegisterBase(parent, def),
1488 dview_(adata, def.id, def.bytes, def.subset_of, def.subset_offset, def.initial_value),
1489 prior_val_dview_(adata, DataView::INVALID_ID, def.bytes),
1490 post_write_noti_data_(this, &prior_val_dview_, &dview_),
1491 post_read_noti_data_(this, &dview_)
1492 {
1493 }
1494
1495 // Override from TreeNode
1496 std::string stringize(bool pretty = false) const override
1497 {
1498 (void)pretty;
1499 std::stringstream ss;
1500 ss << '<' << getLocation() << " " << getNumBits() << " bits ";
1501 if (dview_.isPlaced()) {
1502 ss << getValueAsByteString();
1503 } else {
1505 }
1506 ss << '>';
1507 return ss.str();
1508 }
1509
1514
1520 template <typename T>
1521 inline T dmiRead(index_type idx = 0) const
1522 {
1523 T res;
1524 dmiReadImpl_(&res, sizeof(res), sizeof(res) * idx);
1525 return res;
1526 }
1527
1534 template <typename T>
1535 inline void dmiWrite(T val, index_type idx = 0)
1536 {
1537 dmiWriteImpl_(&val, sizeof(val), sizeof(val) * idx);
1538 }
1539
1546 template <typename T>
1547 inline void writeUnmasked(T val, index_type idx = 0)
1548 {
1549 dmiWriteImpl_(&val, sizeof(T), idx);
1550 }
1551
1552private:
1556 void onBindTreeEarly_() override
1557 {
1558 /* Arch data must laid out before we can get pointer into it */
1559 sparta_assert(dview_.getArchData()->isLaidOut());
1560 raw_data_ptr_ = dview_.getLine()->getRawDataPtr(dview_.getOffset());
1561 }
1562
1563 void read_(void *buf, size_t size, size_t offset=0) override final
1564 {
1565 auto &post_read_noti = getReadNotificationSource();
1566
1567 peek_(buf, size, offset);
1568 if (SPARTA_EXPECT_FALSE(post_read_noti.observed())) {
1569 post_read_noti.postNotification(post_read_noti_data_);
1570 }
1571 }
1572
1573 void peek_(void *buf, size_t size, size_t offset=0) const override final
1574 {
1575 dview_.getLine()->read(
1576 dview_.getOffset() + offset, size, static_cast<uint8_t *>(buf));
1577 }
1578
1579 void dmiRead_(void *buf, size_t size, size_t offset = 0) const override final
1580 {
1581 dmiReadImpl_(buf, size, offset);
1582 }
1583
1584 void write_(const void *buf, size_t size, size_t offset=0) override final
1585 {
1586 auto &post_write_noti = getPostWriteNotificationSource();
1587
1588 if (SPARTA_EXPECT_FALSE(post_write_noti.observed())) {
1589 prior_val_dview_ = dview_;
1590 poke_(buf, size, offset);
1591 post_write_noti.postNotification(post_write_noti_data_);
1592 } else {
1593 poke_(buf, size, offset);
1594 }
1595 }
1596
1597 void poke_(const void *buf, size_t size, size_t offset=0) override final
1598 {
1599 dview_.getLine()->write(
1600 dview_.getOffset() + offset, size, static_cast<const uint8_t *>(buf));
1601 }
1602
1603 void dmiWrite_(const void *buf, size_t size, size_t offset = 0) override final
1604 {
1605 dmiWriteImpl_(buf, size, offset);
1606 }
1607
1608 inline void dmiReadImpl_(void *buf, size_t size, size_t offset = 0) const
1609 {
1610 memcpy(buf, raw_data_ptr_ + offset, size);
1611 }
1612
1613 inline void dmiWriteImpl_(const void *buf, size_t size, size_t offset = 0)
1614 {
1615 memcpy(raw_data_ptr_ + offset, buf, size);
1616 dview_.getLine()->flagDirty();
1617 }
1618
1622 DataView dview_;
1623
1628 DataView prior_val_dview_;
1629
1633 PostWriteNotiSrc::data_type post_write_noti_data_;
1634
1638 ReadNotiSrc::data_type post_read_noti_data_;
1639
1643 uint8_t *raw_data_ptr_ = nullptr;
1644};
1645
1646} // namespace sparta
1647
1648
1650inline std::ostream& operator<<(std::ostream& o, const sparta::Register& reg){
1651 o << reg.stringize();
1652 return o;
1653}
1654
1656inline std::ostream& operator<<(std::ostream& o, const sparta::Register* reg){
1657 if(reg == 0){
1658 o << "null";
1659 }else{
1660 o << reg->stringize();
1661 }
1662 return o;
1663}
1664
1665
1667inline std::ostream& operator<<(std::ostream& o, const sparta::Register::Field& field){
1668 o << field.stringize();
1669 return o;
1670}
1671
1673inline std::ostream& operator<<(std::ostream& o, const sparta::Register::Field* field){
1674 if(field == 0){
1675 o << "null";
1676 }else{
1677 o << field->stringize();
1678 }
1679 return o;
1680}
1681
1682
1684#define SPARTA_REGISTER_BODY \
1685 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.
Cool string utilities.
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....
Definition ArchData.hpp:403
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
void flagDirty()
Allows caller to explicitly flag this line as dirty.
Definition ArchData.hpp:226
Contains a set of contiguous line of architectural data which can be referred to by any architected o...
Definition ArchData.hpp:39
bool isLaidOut() const
Has this ArchData been laid out yet.
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.
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
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
static const std::string DATAVIEW_UNPLACED_STR
String to show instead of a value when representing an unplaced dataview.
Definition DataView.hpp:39
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.
Definition Register.hpp:136
size_type getNumBits() const
Gets number of bits in this field.
Definition Register.hpp:341
void write(access_type t)
Write the field.
Definition Register.hpp:287
const Definition & getDefinition() const
Gets the Definition with which this Field was constructed.
Definition Register.hpp:349
access_type peek() const
Peeks the field.
Definition Register.hpp:276
size_type getHighBit() const
Returns the index of the high bit (inclusive) in this field.
Definition Register.hpp:331
virtual std::string stringize(bool pretty=false) const override
Create a string representation of this node.
Definition Register.hpp:357
static const size_type MAX_FIELD_BITS
Maximum number of bits allowed in a field.
Definition Register.hpp:161
void pokeUnmasked(access_type t)
Poke the field without any read-only mask being applied.
Definition Register.hpp:307
Field(RegisterBase &reg, const Definition &def)
Field Constructor.
Definition Register.hpp:215
access_type read()
Read the field.
Definition Register.hpp:266
bool isReadOnly() const
Returns true if this field is marked read-only.
Definition Register.hpp:336
size_type getLowBit() const
Returns the index of the low bit (inclusive) in this field.
Definition Register.hpp:324
void poke(access_type t)
Poke the field.
Definition Register.hpp:299
uint64_t access_type
Type used for bitfield access.
Definition Register.hpp:156
Base class to represents an architected register of any size that is a power of 2 and greater than 0 ...
Definition Register.hpp:63
size_type getNumBits() const
Gets the size of this register's value in bits.
Definition Register.hpp:872
group_num_type getGroupNum() const
Gets the group number of this register as specified in its definition.
Definition Register.hpp:846
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.
Definition Register.hpp:716
DataView::ident_type ident_type
Identifier to distinguish from other registers in the same RegisterSet.
Definition Register.hpp:72
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...
Definition Register.hpp:930
static constexpr ident_type INVALID_ID
Represents an invalid Register ID.
Definition Register.hpp:681
uint32_t bank_idx_type
Numeric bank identifier for bank lookup.
Definition Register.hpp:98
NotificationSource< PostWriteAccess > PostWriteNotiSrc
Notification type for Register write accesses.
Definition Register.hpp:514
std::function< bool(RegisterBase *, uint64_t)> register_write_callback_type
Register write callback.
Definition Register.hpp:118
T read(index_type idx=0)
Read a value from this register.
Definition Register.hpp:976
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.
Definition Register.hpp:824
void reset(bool unmasked=true)
Reset this register to its default value.
Definition Register.hpp:798
std::vector< const char * > AliasVector
Vector of Register Aliases.
Definition Register.hpp:103
const FieldVector & getFields() const
Const qualified version of getFields.
Definition Register.hpp:921
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.
Definition Register.hpp:953
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.
Definition Register.hpp:986
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.
Definition Register.hpp:127
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.
Definition Register.hpp:92
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...
Definition Register.hpp:894
virtual ~RegisterBase()
Destructor.
Definition Register.hpp:787
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.
Definition Register.hpp:941
std::vector< Field * > FieldVector
Vector of Register Fields.
Definition Register.hpp:108
DataView::offset_type size_type
Size of register and bit or byte offset within register data.
Definition Register.hpp:82
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.
Definition Register.hpp:87
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 Register.hpp:877
Definition::HintsT getHintFlags() const
Returns the hint flags for this type.
Definition Register.hpp:947
size_type getNumBytes() const
Gets the size of this register's value in bytes.
Definition Register.hpp:867
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.
Definition Register.hpp:687
const Definition & getDefinition() const
Gets the definition supplied during the construciton of this Register.
Definition Register.hpp:961
group_idx_type getGroupIdx() const
Gets the group index of this register as specified in its definition.
Definition Register.hpp:862
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.
Definition Register.hpp:840
static constexpr group_num_type GROUP_NUM_NONE
Represents no group much like sparta::TreeNode::GROUP_NAME_NONE.
Definition Register.hpp:684
std::function< sparta::utils::ValidValue< uint64_t >(RegisterBase *)> register_read_callback_type
Register read callback.
Definition Register.hpp:113
FieldVector & getFields()
Gets the full set of register fields.
Definition Register.hpp:916
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.
Definition Register.hpp:853
NotificationSource< ReadAccess > ReadNotiSrc
Notification type for Register read accesses.
Definition Register.hpp:474
virtual void onAddingChild_(TreeNode *child) override
React to child registration.
bool isBanked() const
Is this register banked.
Definition Register.hpp:909
DataView::index_type index_type
Index of read/write access within register.
Definition Register.hpp:77
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.
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 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.
Definition TreeNode.hpp:261
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.
Definition Utils.hpp:142
Describes an architected Register.
Definition Register.hpp:548
const ident_type id
ID. Must be unique within a register set.
Definition Register.hpp:552
const group_num_type group_num
Numeric identifer for the group to which this register belongs. This identifies the group for fast lo...
Definition Register.hpp:573
const char * name
String identifier for this register which distinguishes it from its neighbors. Must adhere to TreeNod...
Definition Register.hpp:559
const size_type subset_offset
Offset (in Bytes) into regster of which this is a subset. subset_offset+(this->bytes) must be <= the ...
Definition Register.hpp:658
const char * desc
Description. Must NOT be NULL.
Definition Register.hpp:596
uint16_t HintsT
Register hint flags. The flags are not part of sparta but should be defined by the model.
Definition Register.hpp:669
const ident_type subset_of
ID of register of which this is a subset. If INVALID_ID, has no effect.
Definition Register.hpp:650
const unsigned char * initial_value
Initial value of this register.
Definition Register.hpp:663
const char ** aliases
Null-terminated array of of char*s (e.g. {"a", "b", 0}). If there are no aliases, this may be 0.
Definition Register.hpp:644
const size_type bytes
Size of this register in bytes. Non-byte multiples are not supported.
Definition Register.hpp:602
const char * group
String name of group in which this register resides (e.g. gpr). Must NOT be NULL. See sparta::TreeNod...
Definition Register.hpp:583
uint16_t RegDomainT
Register Domain. The flags are not part of sparta but should be defined by the model.
Definition Register.hpp:676
const group_idx_type group_idx
Index of register within group. See sparta::TreeNode::TreeNode. Internally, a lookup-vector is built ...
Definition Register.hpp:591
const std::vector< bank_idx_type > bank_membership
Vector of bank indexes of banks in which this register is accessible.
Definition Register.hpp:638
const std::vector< Field::Definition > fields
Vector of field definitions. Use like so for empty fields: { name, group_num,..., bytes,...
Definition Register.hpp:610
Field Definition structure.
Definition Register.hpp:168
size_type high_bit
High bit (inclusive). Must be >= low_bit. (high_bit-low_bit) must be < MAX_FIELD_BITS....
Definition Register.hpp:204
size_type low_bit
Low bit (inclusive)
Definition Register.hpp:203
Definition()=delete
Allow default constructor.
bool read_only
Is this a read-only field.
Definition Register.hpp:205
const char * name
Name - Must ahere to TreeNode::validateName. Must not be NULL.
Definition Register.hpp:201
Definition(const char *_name, const char *_desc, size_type _low_bit, size_type _high_bit)
Limited constructor for backward compatibility.
Definition Register.hpp:178
const char * desc
Description. Must NOT be NULL.
Definition Register.hpp:202
Structure containing data for a Register post-write notification.
Definition Register.hpp:483
const RegisterBase *const reg
Register on which the write access took place.
Definition Register.hpp:496
const DataView *const prior
Value of reg prior to this write.
Definition Register.hpp:501
Structure containing data for a Register pre- or post-read notification.
Definition Register.hpp:451
const DataView *const value
Value just read from reg. This value can also be retrieved through reg.
Definition Register.hpp:468
const RegisterBase *const reg
Register on which the read access took place.
Definition Register.hpp:462