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
682 const bool writable = true;
683 };
684
687
690
693
695 friend class Field;
696
700
721 RegisterBase(TreeNode *parent, const Definition & def)
722 : TreeNode(nullptr,
723 NULL_TO_EMPTY_STR(def.name),
724 NULL_TO_EMPTY_STR(def.group),
725 def.group_idx,
726 NULL_TO_EMPTY_STR(def.desc),
727 false),
728 def_(def),
729 bits_(def.bytes * 8),
730 mask_(computeWriteMask_(&def_)),
731 post_write_noti_(this,
732 "post_write",
733 "Notification immediately after the register has been written",
734 "post_write"),
735 post_read_noti_(this,
736 "post_read",
737 "Notification immediately after the register has been read",
738 "post_read")
739 {
740 if(parent != nullptr){
741 setExpectedParent_(parent);
742 }
743
744 sparta_assert(def.name != 0, "Cannot have a null name in a register definition");
745
746 if(!strcmp(def_.group, GROUP_NAME_NONE) && (def.group_num != GROUP_NUM_NONE)){
747 throw SpartaException("Attempted to add register \"")
748 << getLocation() << "\" which had group number " << def.group_num
749 << " but had group name \"\". A group name is required if a group number is specified.";
750 }
751
752 if(strcmp(def.group, GROUP_NAME_NONE) && (def.group_num == GROUP_NUM_NONE)){
753 throw SpartaException("Attempted to add register \"")
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 << "\"";
757 }
758
759 // Ensure byte-size is valid
760 static_assert(std::is_unsigned<decltype(def.bytes)>::value == true);
761 if(!isPowerOf2(def.bytes) || def.bytes == 0){
762 throw SpartaException("Register \"")
763 << getName() << "\" size in bytes must be a power of 2 larger than 0, is "
764 << def.bytes;
765 }
766
767 // Add all fields
768 for(auto & fdp : def_.fields){
769 addField(fdp);
770 }
771
772 // Add all aliases
773 const char* const * ap = def_.aliases;
774 if(ap != 0){
775 while(*ap != 0){
776 addAlias(*ap); // From sparta::TreeNode
777 ++ap;
778 }
779 }
780
781 // Must add child only after assigning all aliases
782 if(parent != nullptr){
783 parent->addChild(this);
784 }
785 }
786
793 {
794 for(Field* f : owned_fields_){
795 delete f;
796 }
797 }
798
803 void reset(bool unmasked=true) {
804 // Poke the whole value, one-byte at a time
805 for(size_type i=0; i<def_.bytes; i++){
806 if(unmasked){
807 pokeUnmasked(def_.initial_value[i], i);
808 }else{
809 poke(def_.initial_value[i], i);
810 }
811 }
812 }
813
831 owned_fields_.push_back(new Field(*this, fd));
832 return owned_fields_.back();
833 }
834
837
841
845 ident_type getID() const { return def_.id; }
846
851 group_num_type getGroupNum() const { return def_.group_num; }
852
858 std::string getGroupName() const {
859 // Return group. Guaranteed not to be null by Register::Register
860 return def_.group;
861 }
862
867 group_idx_type getGroupIdx() const { return def_.group_idx; }
868
872 size_type getNumBytes() const { return def_.bytes; }
873
877 size_type getNumBits() const { return bits_; }
878
882 size_type getNumFields() const { return (size_type)fields_.size(); }
883
899 bool isInBank(bank_idx_type bank) const {
900 if(isBanked() == false){
901 return true;
902 }
903
904 auto itr = std::find(def_.bank_membership.begin(), def_.bank_membership.end(), bank);
905 return itr != def_.bank_membership.end();
906 }
907
914 bool isBanked() const {
915 return def_.bank_membership.size() != 0;
916 }
917
921 FieldVector& getFields() { return fields_; }
922
926 const FieldVector& getFields() const { return fields_; }
927
935 ident_type getSubsetOf() const { return def_.subset_of; }
936
946 size_type getSubsetOffset() const { return def_.subset_offset; }
947
952 Definition::HintsT getHintFlags() const { return def_.hints; }
953
958 Definition::RegDomainT getRegDomain() const { return def_.regdomain; }
959
966 const Definition& getDefinition() const {
967 return def_;
968 }
969
972
976
980 template <typename T>
982 {
983 T tmp;
984 read(&tmp, sizeof(tmp), idx * sizeof(tmp));
985 return tmp;
986 }
987
992 {
993 if (hasReadCB()) {
994 return read_with_check_cb_(this);
995 } else if (getNumBytes()==4) {
996 return read<uint32_t>();
997 }
998
1000 "read callback only support for 4- and 8-byte registers");
1001 return read<uint64_t>();
1002 }
1003
1010 template <typename T>
1011 void write(T val, index_type idx=0)
1012 {
1013 if (!isWritable()) return;
1014 write(&val, sizeof(val), idx * sizeof(val));
1015 }
1016
1020 template <typename T>
1021 bool writeWithCheck(T val)
1022 {
1023 if (!isWritable()) return false;
1024 if (hasWriteCB()) {
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);
1028 }
1029 write<T>(val);
1030 return true;
1031 }
1032
1038 template <typename T>
1039 void writeUnmasked(T val, index_type idx=0)
1040 {
1041 if (!isWritable()) return;
1042 writeUnmasked(&val, sizeof(val), idx * sizeof(val));
1043 }
1044
1045 template <typename T>
1046 T peek(index_type idx=0) const
1047 {
1048 T tmp;
1049 peek(&tmp, sizeof(tmp), idx * sizeof(tmp));
1050 return tmp;
1051 }
1052
1057 template <typename T>
1058 void poke(T val, index_type idx=0)
1059 {
1060 if (!isWritable()) return;
1061 poke(&val, sizeof(val), idx * sizeof(val));
1062 }
1063
1069 template <typename T>
1070 void pokeUnmasked(T val, index_type idx=0)
1071 {
1072 if (!isWritable()) return;
1073 pokeUnmasked(&val, sizeof(val), idx * sizeof(val));
1074 }
1075
1079 template <typename T>
1080 T dmiRead(index_type idx = 0) const
1081 {
1082 T res;
1083 dmiRead_(&res, sizeof(res), sizeof(res) * idx);
1084 return res;
1085 }
1086
1091 template <typename T>
1092 void dmiWrite(T val, index_type idx = 0)
1093 {
1094 if (!isWritable()) return;
1095 dmiWrite_(&val, sizeof(val), sizeof(val) * idx);
1096 }
1097
1105 template <typename T>
1107 {
1108 sparta_assert((idx + 1) * sizeof(T) <= mask_.getSize());
1109 return *(reinterpret_cast<const T*>(mask_.data()) + idx);
1110 }
1111
1115 bool isWritable() const
1116 {
1117 return def_.writable;
1118 }
1119
1122
1126
1135 std::string getValueAsByteString() const
1136 {
1137 const auto size = getNumBytes();
1138 std::vector<uint8_t> value(size);
1139 peek(value.data(), size, 0);
1140 return utils::bin_to_hexstr(value.data(), size);
1141 }
1142
1151 std::string getWriteMaskAsByteString() const
1152 {
1153 return utils::bin_to_hexstr(
1154 reinterpret_cast<const uint8_t *>(mask_.data()), mask_.getSize());
1155 }
1156
1166 std::string getWriteMaskAsBitString() const
1167 {
1168 return utils::bin_to_bitstr(
1169 reinterpret_cast<const uint8_t *>(mask_.data()), mask_.getSize());
1170 }
1171
1174
1182 Field *getField(const std::string &name)
1183 {
1184 return getChildAs<Field *>(name);
1185 }
1186
1194 const Field *getField(const std::string &name) const
1195 {
1196 return getChildAs<Field *>(name);
1197 }
1198
1202
1203 void read(void *buf, size_t size, size_t offset)
1204 {
1205 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
1206 read_(buf, size, offset);
1207 }
1208
1209 void peek(void *buf, size_t size, size_t offset) const
1210 {
1211 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
1212 peek_(buf, size, offset);
1213 }
1214
1215 void write(const void *buf, size_t size, size_t offset)
1216 {
1217 if (!isWritable()) return;
1218 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
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);
1223 }
1224
1225 void writeUnmasked(const void *buf, size_t size, size_t offset)
1226 {
1227 if (!isWritable()) return;
1228 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
1229 write_(buf, size, offset);
1230 }
1231
1232 void poke(const void *buf, size_t size, size_t offset)
1233 {
1234 if (!isWritable()) return;
1235 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
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);
1240 }
1241
1242 void pokeUnmasked(const void *buf, size_t size, size_t offset)
1243 {
1244 if (!isWritable()) return;
1245 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
1246 poke_(buf, size, offset);
1247 }
1248
1251
1264 {
1265 return post_write_noti_;
1266 }
1267
1280 {
1281 return post_read_noti_;
1282 }
1283
1288 {
1289 read_with_check_cb_ = callback;
1290 }
1291
1295 bool hasReadCB() const
1296 {
1297 return read_with_check_cb_ != nullptr;
1298 }
1299
1304 {
1305 write_with_check_cb_ = callback;
1306 }
1307
1311 bool hasWriteCB() const
1312 {
1313 return write_with_check_cb_ != nullptr;
1314 }
1315
1316protected:
1317
1327 virtual void onAddingChild_(TreeNode* child) override {
1328 Field* fld = dynamic_cast<Field*>(child);
1329 if(nullptr != fld){
1330 // Add Field to fields_ list for tracking.
1331 fields_.push_back(fld);
1332 }
1333 }
1334
1335 virtual void read_(void *buf, size_t size, size_t offset = 0) = 0;
1336
1337 virtual void peek_(void *buf, size_t size, size_t offset = 0) const = 0;
1338
1339 virtual void write_(const void *buf, size_t size, size_t offset = 0) = 0;
1340
1341 virtual void poke_(const void *buf, size_t size, size_t offset = 0) = 0;
1342
1343 virtual void dmiRead_(void *buf, size_t size, size_t offset = 0) const
1344 {
1345 (void)buf; (void)size; (void)offset;
1346 sparta_assert(!"Register DMI not supported");
1347 }
1348
1349 virtual void dmiWrite_(const void *buf, size_t size, size_t offset = 0)
1350 {
1351 (void)buf; (void)size; (void)offset;
1352 sparta_assert(!"Register DMI not supported");
1353 }
1354
1355private:
1356 RegisterBits computeWriteMask_(const Definition *def) const
1357 {
1358 if(!isPowerOf2(def->bytes)) {
1359 throw SpartaException("Register \"")
1360 << getName() << "\" size in bytes must be a power of 2 larger than 0, is "
1361 << def->bytes;
1362 }
1363
1364 const auto mask_size = def->bytes;
1365 RegisterBits write_mask(mask_size);
1366 RegisterBits partial_mask(mask_size);
1367 partial_mask.fill(0xff);
1368
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;
1374
1375 write_mask |= ((partial_mask >> shift_down) << shift_up);
1376 }
1377 }
1378
1379 return ~write_mask;
1380 }
1381
1382 RegisterBits peekRegisterBits_(size_t size, size_t offset=0) const
1383 {
1384 RegisterBits bits(size);
1385 peek_(bits.data(), size, offset);
1386 return bits;
1387 }
1388
1392 const Definition def_;
1393
1398 FieldVector owned_fields_;
1399
1403 FieldVector fields_;
1404
1408 const size_type bits_;
1409
1413 const RegisterBits mask_;
1414
1418 PostWriteNotiSrc post_write_noti_;
1419
1423 ReadNotiSrc post_read_noti_;
1424
1428 register_read_callback_type read_with_check_cb_ {nullptr};
1429 register_write_callback_type write_with_check_cb_ {nullptr};
1430}; // class RegisterBase
1431
1432inline bool operator==(const RegisterBase::Definition &a,
1433 const RegisterBase::Definition &b)
1434{
1435 if (a.id != b.id) {
1436 return false;
1437 }
1438 if (!utils::strcmp_with_null(a.name, b.name)) {
1439 return false;
1440 }
1441 if (a.group_num != b.group_num) {
1442 return false;
1443 }
1444 if (!utils::strcmp_with_null(a.group, b.group)) {
1445 return false;
1446 }
1447 if (a.group_idx != b.group_idx) {
1448 return false;
1449 }
1450 if (!utils::strcmp_with_null(a.desc, b.desc)) {
1451 return false;
1452 }
1453 if (a.bytes != b.bytes) {
1454 return false;
1455 }
1456
1457 /* TODO: Compare fields. This require a == operator for Field::Definition */
1458
1459 if (a.bank_membership != b.bank_membership) {
1460 return false;
1461 }
1462
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)) {
1468 return false;
1469 }
1470 }
1471 } else if (!(a_aliases == nullptr && b_aliases == nullptr)) {
1472 return false;
1473 }
1474
1475 if (a.subset_of != b.subset_of) {
1476 return false;
1477 }
1478 if (!utils::strcmp_with_null((const char *)a.initial_value, (const char *)b.initial_value)) {
1479 return false;
1480 }
1481 if (a.hints != b.hints) {
1482 return false;
1483 }
1484 if (a.regdomain != b.regdomain) {
1485 return false;
1486 }
1487
1488 return true;
1489}
1490
1491inline bool operator!=(const RegisterBase::Definition &a,
1492 const RegisterBase::Definition &b)
1493{
1494 return !(a == b);
1495}
1496
1506{
1507public:
1508 Register(TreeNode *parent, const Definition def, ArchData *adata) :
1509 RegisterBase(parent, def),
1510 dview_(adata, def.id, def.bytes, def.subset_of, def.subset_offset, def.initial_value),
1511 prior_val_dview_(adata, DataView::INVALID_ID, def.bytes),
1512 post_write_noti_data_(this, &prior_val_dview_, &dview_),
1513 post_read_noti_data_(this, &dview_)
1514 {
1515 }
1516
1517 // Override from TreeNode
1518 std::string stringize(bool pretty = false) const override
1519 {
1520 (void)pretty;
1521 std::stringstream ss;
1522 ss << '<' << getLocation() << " " << getNumBits() << " bits ";
1523 if (dview_.isPlaced()) {
1524 ss << getValueAsByteString();
1525 } else {
1527 }
1528 ss << '>';
1529 return ss.str();
1530 }
1531
1536
1542 template <typename T>
1543 inline T dmiRead(index_type idx = 0) const
1544 {
1545 T res;
1546 dmiReadImpl_(&res, sizeof(res), sizeof(res) * idx);
1547 return res;
1548 }
1549
1556 template <typename T>
1557 inline void dmiWrite(T val, index_type idx = 0)
1558 {
1559 if (!isWritable()) return;
1560 dmiWriteImpl_(&val, sizeof(val), sizeof(val) * idx);
1561 }
1562
1569 template <typename T>
1570 inline void writeUnmasked(T val, index_type idx = 0)
1571 {
1572 if (!isWritable()) return;
1573 dmiWriteImpl_(&val, sizeof(T), idx);
1574 }
1575
1576private:
1580 void onBindTreeEarly_() override
1581 {
1582 /* Arch data must laid out before we can get pointer into it */
1583 sparta_assert(dview_.getArchData()->isLaidOut());
1584 raw_data_ptr_ = dview_.getLine()->getRawDataPtr(dview_.getOffset());
1585 }
1586
1587 void read_(void *buf, size_t size, size_t offset=0) override final
1588 {
1589 auto &post_read_noti = getReadNotificationSource();
1590
1591 peek_(buf, size, offset);
1592 if (SPARTA_EXPECT_FALSE(post_read_noti.observed())) {
1593 post_read_noti.postNotification(post_read_noti_data_);
1594 }
1595 }
1596
1597 void peek_(void *buf, size_t size, size_t offset=0) const override final
1598 {
1599 dview_.getLine()->read(
1600 dview_.getOffset() + offset, size, static_cast<uint8_t *>(buf));
1601 }
1602
1603 void dmiRead_(void *buf, size_t size, size_t offset = 0) const override final
1604 {
1605 dmiReadImpl_(buf, size, offset);
1606 }
1607
1608 void write_(const void *buf, size_t size, size_t offset=0) override final
1609 {
1610 if (!isWritable()) return;
1611 auto &post_write_noti = getPostWriteNotificationSource();
1612
1613 if (SPARTA_EXPECT_FALSE(post_write_noti.observed())) {
1614 prior_val_dview_ = dview_;
1615 poke_(buf, size, offset);
1616 post_write_noti.postNotification(post_write_noti_data_);
1617 } else {
1618 poke_(buf, size, offset);
1619 }
1620 }
1621
1622 void poke_(const void *buf, size_t size, size_t offset=0) override final
1623 {
1624 if (!isWritable()) return;
1625 dview_.getLine()->write(
1626 dview_.getOffset() + offset, size, static_cast<const uint8_t *>(buf));
1627 }
1628
1629 void dmiWrite_(const void *buf, size_t size, size_t offset = 0) override final
1630 {
1631 if (!isWritable()) return;
1632 dmiWriteImpl_(buf, size, offset);
1633 }
1634
1635 inline void dmiReadImpl_(void *buf, size_t size, size_t offset = 0) const
1636 {
1637 memcpy(buf, raw_data_ptr_ + offset, size);
1638 }
1639
1640 inline void dmiWriteImpl_(const void *buf, size_t size, size_t offset = 0)
1641 {
1642 if (!isWritable()) return;
1643 memcpy(raw_data_ptr_ + offset, buf, size);
1644 dview_.getLine()->flagDirty();
1645 }
1646
1650 DataView dview_;
1651
1656 DataView prior_val_dview_;
1657
1661 PostWriteNotiSrc::data_type post_write_noti_data_;
1662
1666 ReadNotiSrc::data_type post_read_noti_data_;
1667
1671 uint8_t *raw_data_ptr_ = nullptr;
1672};
1673
1674} // namespace sparta
1675
1676
1678inline std::ostream& operator<<(std::ostream& o, const sparta::Register& reg){
1679 o << reg.stringize();
1680 return o;
1681}
1682
1684inline std::ostream& operator<<(std::ostream& o, const sparta::Register* reg){
1685 if(reg == 0){
1686 o << "null";
1687 }else{
1688 o << reg->stringize();
1689 }
1690 return o;
1691}
1692
1693
1695inline std::ostream& operator<<(std::ostream& o, const sparta::Register::Field& field){
1696 o << field.stringize();
1697 return o;
1698}
1699
1701inline std::ostream& operator<<(std::ostream& o, const sparta::Register::Field* field){
1702 if(field == 0){
1703 o << "null";
1704 }else{
1705 o << field->stringize();
1706 }
1707 return o;
1708}
1709
1710
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.
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:877
group_num_type getGroupNum() const
Gets the group number of this register as specified in its definition.
Definition Register.hpp:851
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:721
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:935
static constexpr ident_type INVALID_ID
Represents an invalid Register ID.
Definition Register.hpp:686
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:981
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:829
void reset(bool unmasked=true)
Reset this register to its default value.
Definition Register.hpp:803
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:926
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:958
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:991
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:899
virtual ~RegisterBase()
Destructor.
Definition Register.hpp:792
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:946
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:882
Definition::HintsT getHintFlags() const
Returns the hint flags for this type.
Definition Register.hpp:952
size_type getNumBytes() const
Gets the size of this register's value in bytes.
Definition Register.hpp:872
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:692
const Definition & getDefinition() const
Gets the definition supplied during the construciton of this Register.
Definition Register.hpp:966
group_idx_type getGroupIdx() const
Gets the group index of this register as specified in its definition.
Definition Register.hpp:867
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:845
static constexpr group_num_type GROUP_NUM_NONE
Represents no group much like sparta::TreeNode::GROUP_NAME_NONE.
Definition Register.hpp:689
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:921
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:858
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:914
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 bool writable
Writable flag, taken from the register definition.
Definition Register.hpp:682
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