The Sparta Modeling Framework
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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#include <cassert>
13
15#include "sparta/functional/DataView.hpp"
16#include "sparta/functional/RegisterBits.hpp"
17#include "sparta/utils/Utils.hpp"
18#include "sparta/log/NotificationSource.hpp"
23
24namespace sparta
25{
26
63class RegisterBase : public TreeNode
64{
65
66public:
67 class Field;
68
74
79
84
88 typedef uint32_t group_num_type;
89
94
99 typedef uint32_t bank_idx_type;
100
104 typedef std::vector<const char*> AliasVector;
105
109 typedef std::vector<Field*> FieldVector;
110
114 typedef std::function<sparta::utils::ValidValue<uint64_t>(RegisterBase*)> register_read_callback_type;
115
119 typedef std::function<bool(RegisterBase*, uint64_t)> register_write_callback_type;
120
123
128 static constexpr bank_idx_type BANK_IDX_DEFAULT = 0;
129
136 class Field : public TreeNode
137 {
138 RegisterBits computeFieldMask_(uint32_t start, uint32_t end, uint32_t reg_size)
139 {
140 const auto num_ones = start - end + 1;
141 RegisterBits mask(reg_size);
142 // For 31-0:
143
144 // max() & (max() >> ((8 * 8) - 31))
145 const uint64_t masked_bits = std::numeric_limits<uint64_t>::max() &
146 (std::numeric_limits<uint64_t>::max() >> ((sizeof(uint64_t) * CHAR_BIT) - num_ones));
147 mask.set(masked_bits);
148 mask <<= end;
149 return mask;
150 }
151
152 public:
153
157 typedef uint64_t access_type;
158
162 static const size_type MAX_FIELD_BITS = sizeof(access_type) * 8;
163
169 {
173 Definition() = delete;
174
179 Definition(const char* _name,
180 const char* _desc,
181 size_type _low_bit,
182 size_type _high_bit) :
183 name(_name),
184 desc(_desc),
185 low_bit(_low_bit),
186 high_bit(_high_bit),
187 read_only(false)
188 {;}
189
190 Definition(const char* _name,
191 const char* _desc,
192 size_type _low_bit,
193 size_type _high_bit,
194 bool _read_only) :
195 name(_name),
196 desc(_desc),
197 low_bit(_low_bit),
198 high_bit(_high_bit),
199 read_only(_read_only)
200 {;}
201
202 const char* name;
203 const char* desc;
207 };
208
216 Field(RegisterBase &reg, const Definition &def) :
217 TreeNode(NULL_TO_EMPTY_STR(def.name), TreeNode::GROUP_NAME_NONE,
218 TreeNode::GROUP_IDX_NONE, NULL_TO_EMPTY_STR(def.desc)),
219 reg_(reg),
220 def_(def),
221 reg_size_(reg_.getNumBytes()),
222 field_mask_(computeFieldMask_(def.high_bit, def.low_bit, reg_.getNumBytes())),
223 not_field_mask_(~field_mask_)
224 {
225 setExpectedParent_(&reg);
226
227 sparta_assert(def_.name != 0, "Register::Field::Definition::name cannot be empty");
228
229 if(def_.high_bit < def_.low_bit){
230 throw SpartaException("Register Field ")
231 << getLocation() << " definition contains high bit (" << def_.high_bit
232 << ") less than a low bit (" << def_.low_bit << ")";
233 }
234
235 if(def_.low_bit >= reg.getNumBits()){
236 throw SpartaException("Register Field ")
237 << getLocation() << " definition contains a low bit (" << def_.low_bit
238 << ") greater than or equal to the number of bits in the register ("
239 << reg.getNumBits() << ")";
240 }
241 if(def_.high_bit >= reg.getNumBits()){
242 throw SpartaException("Register Field ")
243 << getLocation() << " definition contains a high bit (" << def_.high_bit
244 << ") greater than or equal to the number of bits in the register ("
245 << reg.getNumBits() << ")";
246 }
247
249 throw SpartaException("Cannot currently support more than ")
250 << (size_type)MAX_FIELD_BITS << "bit-wide fields. "
251 << "Problem with field \"" << getLocation() << "\"";
252 }
253
254 // Add self as child after successful initialization
255 reg.addChild(this);
256 }
257
261
268 {
269 return ((readBitArray_() & field_mask_) >> getLowBit()).dataAs<access_type>();
270 }
271
278 {
279 return ((peekBitArray_() & field_mask_) >> getLowBit()).dataAs<access_type>();
280 }
281
289 {
290 write_(newRegisterValue_(t));
291 }
292
301 {
302 poke_(newRegisterValue_(t));
303 }
304
309 {
310 pokeUnmasked_(newRegisterValue_(t));
311 }
312
315
319
325 size_type getLowBit() const { return def_.low_bit; }
326
332 size_type getHighBit() const { return def_.high_bit; }
333
337 bool isReadOnly() const { return def_.read_only; }
338
343 {
344 return getHighBit() - getLowBit() + 1;
345 }
346
350 const Definition& getDefinition() const {
351 return def_;
352 }
353
356
357 // Override from TreeNode
358 virtual std::string stringize(bool pretty=false) const override{
359 (void) pretty;
360 std::stringstream ss;
361 ss << '<' << getLocation() << " [" << def_.low_bit << "-"
362 << def_.high_bit << "] " << getNumBits();
363 ss << " bits LE:0x" << std::hex << peek();
364 if(def_.read_only){
365 ss << " READ-ONLY";
366 }
367 ss << '>';
368 return ss.str();
369 }
370
371 private:
372 RegisterBits readBitArray_() const
373 {
374 RegisterBits reg_bits(reg_size_);
375 reg_.read(reg_bits.data(), reg_size_, 0);
376 return reg_bits;
377 }
378
379 RegisterBits peekBitArray_() const
380 {
381 RegisterBits reg_bits(reg_size_);
382 reg_.peek(reg_bits.data(), reg_size_, 0);
383 return reg_bits;
384 }
385
386 void write_(const RegisterBits &value)
387 {
388 reg_.write(value.data(), value.getSize(), 0);
389 }
390
391 void poke_(const RegisterBits &value)
392 {
393 reg_.poke(value.data(), value.getSize(), 0);
394 }
395
396 void pokeUnmasked_(const RegisterBits &value)
397 {
398 reg_.pokeUnmasked(value.data(), value.getSize(), 0);
399 }
400
401 RegisterBits newRegisterValue_(access_type value) const
402 {
403 const auto old_register_value = peekBitArray_();
404
405 RegisterBits field_value_to_be_written_shifted(std::max((size_t)reg_size_, sizeof(access_type)), value);
406 field_value_to_be_written_shifted <<= getLowBit();
407
408 // Check to see if the number of bits being written to the
409 // field is larger than the field itself.
410 sparta_assert((field_value_to_be_written_shifted & not_field_mask_).none(),
411 "Value of " << value << " too large for bit field "
412 << getLocation() << " of size " << getNumBits());
413
414 return (old_register_value & not_field_mask_) | field_value_to_be_written_shifted;
415 }
416
420 RegisterBase &reg_;
421
425 const Definition &def_;
426
430 const RegisterBase::size_type reg_size_ = 0;
431
435 const RegisterBits field_mask_;
436
440 const RegisterBits not_field_mask_;
441
442 }; // class Field
443
452 {
453 ReadAccess() = delete;
454
455 ReadAccess(const RegisterBase *_reg, const DataView *_value_dview)
456 : reg(_reg), value(_value_dview)
457 {
458 }
459
463 const RegisterBase *const reg;
464
469 const DataView *const value;
470 };
471
476
484 {
485 PostWriteAccess() = delete;
486
487 PostWriteAccess(const RegisterBase *_reg,
488 const DataView *_prior_dview,
489 const DataView *_final_dview)
490 : reg(_reg), prior(_prior_dview), final(_final_dview)
491 {
492 }
493
497 const RegisterBase *const reg;
498
502 const DataView *const prior;
503
509 const DataView *const final;
510 };
511
516
549 {
554
560 const char* name;
561
575
584 const char* group;
585
593
597 const char* desc;
598
604
611 const std::vector<Field::Definition> fields;
612
639 const std::vector<bank_idx_type> bank_membership;
640
645 const char** aliases;
646
652
660
664 const unsigned char* initial_value;
665
670 typedef uint16_t HintsT;
671 const HintsT hints;
672
677 typedef uint16_t RegDomainT;
678 const RegDomainT regdomain;
679
683 const bool writable = true;
684 };
685
688
691
694
696 friend class Field;
697
701
722 RegisterBase(TreeNode *parent, const Definition & def)
723 : TreeNode(nullptr,
724 NULL_TO_EMPTY_STR(def.name),
725 NULL_TO_EMPTY_STR(def.group),
726 def.group_idx,
727 NULL_TO_EMPTY_STR(def.desc),
728 false),
729 def_(def),
730 bits_(def.bytes * 8),
731 mask_(computeWriteMask_(&def_)),
732 post_write_noti_(this,
733 "post_write",
734 "Notification immediately after the register has been written",
735 "post_write"),
736 post_read_noti_(this,
737 "post_read",
738 "Notification immediately after the register has been read",
739 "post_read")
740 {
741 if(parent != nullptr){
742 setExpectedParent_(parent);
743 }
744
745 sparta_assert(def.name != 0, "Cannot have a null name in a register definition");
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 " << def.group_num
750 << " but had group name \"\". A group name is required if a group number is specified.";
751 }
752
753 if(strcmp(def.group, GROUP_NAME_NONE) && (def.group_num == GROUP_NUM_NONE)){
754 throw SpartaException("Attempted to add register \"")
755 << getLocation() << "\" which had group number GROUP_NUM_NONE"
756 << " but had group name \"" << def.group
757 << "\". A group number is required if a group name is specified.\"" << GROUP_NAME_NONE << "\"";
758 }
759
760 // Ensure byte-size is valid
761 static_assert(std::is_unsigned<decltype(def.bytes)>::value == true);
762 if(!isPowerOf2(def.bytes) || def.bytes == 0){
763 throw SpartaException("Register \"")
764 << getName() << "\" size in bytes must be a power of 2 larger than 0, is "
765 << def.bytes;
766 }
767
768 // Add all fields
769 for(auto & fdp : def_.fields){
770 addField(fdp);
771 }
772
773 // Add all aliases
774 const char* const * ap = def_.aliases;
775 if(ap != 0){
776 while(*ap != 0){
777 addAlias(*ap); // From sparta::TreeNode
778 ++ap;
779 }
780 }
781
782 // Must add child only after assigning all aliases
783 if(parent != nullptr){
784 parent->addChild(this);
785 }
786 }
787
794 {
795 for(Field* f : owned_fields_){
796 delete f;
797 }
798 }
799
804 void reset(bool unmasked=true) {
805 // Poke the whole value, one-byte at a time
806 for(size_type i=0; i<def_.bytes; i++){
807 if(unmasked){
808 pokeUnmasked(def_.initial_value[i], i);
809 }else{
810 poke(def_.initial_value[i], i);
811 }
812 }
813 }
814
832 owned_fields_.push_back(new Field(*this, fd));
833 return owned_fields_.back();
834 }
835
838
842
846 ident_type getID() const { return def_.id; }
847
852 group_num_type getGroupNum() const { return def_.group_num; }
853
859 std::string getGroupName() const {
860 // Return group. Guaranteed not to be null by Register::Register
861 return def_.group;
862 }
863
868 group_idx_type getGroupIdx() const { return def_.group_idx; }
869
873 size_type getNumBytes() const { return def_.bytes; }
874
878 size_type getNumBits() const { return bits_; }
879
883 size_type getNumFields() const { return (size_type)fields_.size(); }
884
900 bool isInBank(bank_idx_type bank) const {
901 if(isBanked() == false){
902 return true;
903 }
904
905 auto itr = std::find(def_.bank_membership.begin(), def_.bank_membership.end(), bank);
906 return itr != def_.bank_membership.end();
907 }
908
915 bool isBanked() const {
916 return def_.bank_membership.size() != 0;
917 }
918
922 FieldVector& getFields() { return fields_; }
923
927 const FieldVector& getFields() const { return fields_; }
928
936 ident_type getSubsetOf() const { return def_.subset_of; }
937
947 size_type getSubsetOffset() const { return def_.subset_offset; }
948
953 Definition::HintsT getHintFlags() const { return def_.hints; }
954
959 Definition::RegDomainT getRegDomain() const { return def_.regdomain; }
960
967 const Definition& getDefinition() const {
968 return def_;
969 }
970
973
977
981 template <typename T>
983 {
984 T tmp;
985 read(&tmp, sizeof(tmp), idx * sizeof(tmp));
986 return tmp;
987 }
988
993 {
994 if (hasReadCB()) {
995 return read_with_check_cb_(this);
996 } else if (getNumBytes()==4) {
997 return read<uint32_t>();
998 }
999
1001 "read callback only support for 4- and 8-byte registers");
1002 return read<uint64_t>();
1003 }
1004
1011 template <typename T>
1012 void write(T val, index_type idx=0)
1013 {
1014 assert(isWritable());
1015 write(&val, sizeof(val), idx * sizeof(val));
1016 }
1017
1021 template <typename T>
1022 bool writeWithCheck(T val)
1023 {
1024 assert(isWritable());
1025 if (hasWriteCB()) {
1026 static_assert((sizeof(T)==4) || (sizeof(T)==8),
1027 "write callback only support for 4- and 8-byte registers");
1028 return write_with_check_cb_(this, val);
1029 }
1030 write<T>(val);
1031 return true;
1032 }
1033
1039 template <typename T>
1040 void writeUnmasked(T val, index_type idx=0)
1041 {
1042 assert(isWritable());
1043 writeUnmasked(&val, sizeof(val), idx * sizeof(val));
1044 }
1045
1046 template <typename T>
1047 T peek(index_type idx=0) const
1048 {
1049 T tmp;
1050 peek(&tmp, sizeof(tmp), idx * sizeof(tmp));
1051 return tmp;
1052 }
1053
1058 template <typename T>
1059 void poke(T val, index_type idx=0)
1060 {
1061 assert(isWritable());
1062 poke(&val, sizeof(val), idx * sizeof(val));
1063 }
1064
1070 template <typename T>
1071 void pokeUnmasked(T val, index_type idx=0)
1072 {
1073 assert(isWritable());
1074 pokeUnmasked(&val, sizeof(val), idx * sizeof(val));
1075 }
1076
1080 template <typename T>
1081 T dmiRead(index_type idx = 0) const
1082 {
1083 T res;
1084 dmiRead_(&res, sizeof(res), sizeof(res) * idx);
1085 return res;
1086 }
1087
1092 template <typename T>
1093 void dmiWrite(T val, index_type idx = 0)
1094 {
1095 assert(isWritable());
1096 dmiWrite_(&val, sizeof(val), sizeof(val) * idx);
1097 }
1098
1106 template <typename T>
1108 {
1109 sparta_assert((idx + 1) * sizeof(T) <= mask_.getSize());
1110 return *(reinterpret_cast<const T*>(mask_.data()) + idx);
1111 }
1112
1116 bool isWritable() const
1117 {
1118 return def_.writable;
1119 }
1120
1123
1127
1136 std::string getValueAsByteString() const
1137 {
1138 const auto size = getNumBytes();
1139 std::vector<uint8_t> value(size);
1140 peek(value.data(), size, 0);
1141 return utils::bin_to_hexstr(value.data(), size);
1142 }
1143
1152 std::string getWriteMaskAsByteString() const
1153 {
1154 return utils::bin_to_hexstr(
1155 reinterpret_cast<const uint8_t *>(mask_.data()), mask_.getSize());
1156 }
1157
1167 std::string getWriteMaskAsBitString() const
1168 {
1169 return utils::bin_to_bitstr(
1170 reinterpret_cast<const uint8_t *>(mask_.data()), mask_.getSize());
1171 }
1172
1175
1183 Field *getField(const std::string &name)
1184 {
1185 return getChildAs<Field *>(name);
1186 }
1187
1195 const Field *getField(const std::string &name) const
1196 {
1197 return getChildAs<Field *>(name);
1198 }
1199
1203
1204 void read(void *buf, size_t size, size_t offset)
1205 {
1206 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
1207 read_(buf, size, offset);
1208 }
1209
1210 void peek(void *buf, size_t size, size_t offset) const
1211 {
1212 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
1213 peek_(buf, size, offset);
1214 }
1215
1216 void write(const void *buf, size_t size, size_t offset)
1217 {
1218 assert(isWritable());
1219 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
1220 RegisterBits val(reinterpret_cast<const uint8_t *>(buf), size);
1221 RegisterBits mask = mask_ >> 8 * offset;
1222 RegisterBits old = (peekRegisterBits_(size, offset) & ~mask) | (val & mask);
1223 write_(old.data(), size, offset);
1224 }
1225
1226 void writeUnmasked(const void *buf, size_t size, size_t offset)
1227 {
1228 assert(isWritable());
1229 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
1230 write_(buf, size, offset);
1231 }
1232
1233 void poke(const void *buf, size_t size, size_t offset)
1234 {
1235 assert(isWritable());
1236 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
1237 RegisterBits val(reinterpret_cast<const uint8_t *>(buf), size);
1238 RegisterBits mask = mask_ >> 8 * offset;
1239 RegisterBits old = (peekRegisterBits_(size, offset) & ~mask) | (val & mask);
1240 poke_(old.data(), size, offset);
1241 }
1242
1243 void pokeUnmasked(const void *buf, size_t size, size_t offset)
1244 {
1245 assert(isWritable());
1246 sparta_assert(offset + size <= getNumBytes(), "Access out of bounds");
1247 poke_(buf, size, offset);
1248 }
1249
1252
1265 {
1266 return post_write_noti_;
1267 }
1268
1281 {
1282 return post_read_noti_;
1283 }
1284
1289 {
1290 read_with_check_cb_ = callback;
1291 }
1292
1296 bool hasReadCB() const
1297 {
1298 return read_with_check_cb_ != nullptr;
1299 }
1300
1305 {
1306 write_with_check_cb_ = callback;
1307 }
1308
1312 bool hasWriteCB() const
1313 {
1314 return write_with_check_cb_ != nullptr;
1315 }
1316
1317protected:
1318
1328 virtual void onAddingChild_(TreeNode* child) override {
1329 Field* fld = dynamic_cast<Field*>(child);
1330 if(nullptr != fld){
1331 // Add Field to fields_ list for tracking.
1332 fields_.push_back(fld);
1333 }
1334 }
1335
1336 virtual void read_(void *buf, size_t size, size_t offset = 0) = 0;
1337
1338 virtual void peek_(void *buf, size_t size, size_t offset = 0) const = 0;
1339
1340 virtual void write_(const void *buf, size_t size, size_t offset = 0) = 0;
1341
1342 virtual void poke_(const void *buf, size_t size, size_t offset = 0) = 0;
1343
1344 virtual void dmiRead_(void *buf, size_t size, size_t offset = 0) const
1345 {
1346 (void)buf; (void)size; (void)offset;
1347 sparta_assert(!"Register DMI not supported");
1348 }
1349
1350 virtual void dmiWrite_(const void *buf, size_t size, size_t offset = 0)
1351 {
1352 (void)buf; (void)size; (void)offset;
1353 sparta_assert(!"Register DMI not supported");
1354 }
1355
1356private:
1357 RegisterBits computeWriteMask_(const Definition *def) const
1358 {
1359 if(!isPowerOf2(def->bytes)) {
1360 throw SpartaException("Register \"")
1361 << getName() << "\" size in bytes must be a power of 2 larger than 0, is "
1362 << def->bytes;
1363 }
1364
1365 const auto mask_size = def->bytes;
1366 RegisterBits write_mask(mask_size);
1367 RegisterBits partial_mask(mask_size);
1368 partial_mask.fill(0xff);
1369
1370 for (auto &fdp : def->fields) {
1371 if (fdp.read_only) {
1372 const uint64_t field_size = fdp.high_bit - fdp.low_bit + 1;
1373 const uint64_t shift_down = 8 * mask_size - field_size;
1374 const uint64_t shift_up = fdp.low_bit;
1375
1376 write_mask |= ((partial_mask >> shift_down) << shift_up);
1377 }
1378 }
1379
1380 return ~write_mask;
1381 }
1382
1383 RegisterBits peekRegisterBits_(size_t size, size_t offset=0) const
1384 {
1385 RegisterBits bits(size);
1386 peek_(bits.data(), size, offset);
1387 return bits;
1388 }
1389
1393 const Definition def_;
1394
1399 FieldVector owned_fields_;
1400
1404 FieldVector fields_;
1405
1409 const size_type bits_;
1410
1414 const RegisterBits mask_;
1415
1419 PostWriteNotiSrc post_write_noti_;
1420
1424 ReadNotiSrc post_read_noti_;
1425
1429 register_read_callback_type read_with_check_cb_ {nullptr};
1430 register_write_callback_type write_with_check_cb_ {nullptr};
1431}; // class RegisterBase
1432
1433inline bool operator==(const RegisterBase::Definition &a,
1434 const RegisterBase::Definition &b)
1435{
1436 if (a.id != b.id) {
1437 return false;
1438 }
1439 if (!utils::strcmp_with_null(a.name, b.name)) {
1440 return false;
1441 }
1442 if (a.group_num != b.group_num) {
1443 return false;
1444 }
1445 if (!utils::strcmp_with_null(a.group, b.group)) {
1446 return false;
1447 }
1448 if (a.group_idx != b.group_idx) {
1449 return false;
1450 }
1451 if (!utils::strcmp_with_null(a.desc, b.desc)) {
1452 return false;
1453 }
1454 if (a.bytes != b.bytes) {
1455 return false;
1456 }
1457
1458 /* TODO: Compare fields. This require a == operator for Field::Definition */
1459
1460 if (a.bank_membership != b.bank_membership) {
1461 return false;
1462 }
1463
1464 auto a_aliases = a.aliases;
1465 auto b_aliases = b.aliases;
1466 if (a_aliases != nullptr && b_aliases != nullptr) {
1467 for (; *a_aliases != 0 || *b_aliases != 0; ++a_aliases, ++b_aliases) {
1468 if (!utils::strcmp_with_null(*a_aliases, *b_aliases)) {
1469 return false;
1470 }
1471 }
1472 } else if (!(a_aliases == nullptr && b_aliases == nullptr)) {
1473 return false;
1474 }
1475
1476 if (a.subset_of != b.subset_of) {
1477 return false;
1478 }
1479 if (!utils::strcmp_with_null((const char *)a.initial_value, (const char *)b.initial_value)) {
1480 return false;
1481 }
1482 if (a.hints != b.hints) {
1483 return false;
1484 }
1485 if (a.regdomain != b.regdomain) {
1486 return false;
1487 }
1488
1489 return true;
1490}
1491
1492inline bool operator!=(const RegisterBase::Definition &a,
1493 const RegisterBase::Definition &b)
1494{
1495 return !(a == b);
1496}
1497
1507{
1508public:
1509 Register(TreeNode *parent, const Definition def, ArchData *adata) :
1510 RegisterBase(parent, def),
1511 dview_(adata, def.id, def.bytes, def.subset_of, def.subset_offset, def.initial_value),
1512 prior_val_dview_(adata, DataView::INVALID_ID, def.bytes),
1513 post_write_noti_data_(this, &prior_val_dview_, &dview_),
1514 post_read_noti_data_(this, &dview_)
1515 {
1516 }
1517
1518 // Override from TreeNode
1519 std::string stringize(bool pretty = false) const override
1520 {
1521 (void)pretty;
1522 std::stringstream ss;
1523 ss << '<' << getLocation() << " " << getNumBits() << " bits ";
1524 if (dview_.isPlaced()) {
1525 ss << getValueAsByteString();
1526 } else {
1528 }
1529 ss << '>';
1530 return ss.str();
1531 }
1532
1537
1543 template <typename T>
1544 inline T dmiRead(index_type idx = 0) const
1545 {
1546 T res;
1547 dmiReadImpl_(&res, sizeof(res), sizeof(res) * idx);
1548 return res;
1549 }
1550
1557 template <typename T>
1558 inline void dmiWrite(T val, index_type idx = 0)
1559 {
1560 assert(isWritable());
1561 dmiWriteImpl_(&val, sizeof(val), sizeof(val) * idx);
1562 }
1563
1570 template <typename T>
1571 inline void writeUnmasked(T val, index_type idx = 0)
1572 {
1573 assert(isWritable());
1574 dmiWriteImpl_(&val, sizeof(T), idx);
1575 }
1576
1577private:
1581 void onBindTreeEarly_() override
1582 {
1583 /* Arch data must laid out before we can get pointer into it */
1584 sparta_assert(dview_.getArchData()->isLaidOut());
1585 raw_data_ptr_ = dview_.getLine()->getRawDataPtr(dview_.getOffset());
1586 }
1587
1588 void read_(void *buf, size_t size, size_t offset=0) override final
1589 {
1590 auto &post_read_noti = getReadNotificationSource();
1591
1592 peek_(buf, size, offset);
1593 if (SPARTA_EXPECT_FALSE(post_read_noti.observed())) {
1594 post_read_noti.postNotification(post_read_noti_data_);
1595 }
1596 }
1597
1598 void peek_(void *buf, size_t size, size_t offset=0) const override final
1599 {
1600 dview_.getLine()->read(
1601 dview_.getOffset() + offset, size, static_cast<uint8_t *>(buf));
1602 }
1603
1604 void dmiRead_(void *buf, size_t size, size_t offset = 0) const override final
1605 {
1606 dmiReadImpl_(buf, size, offset);
1607 }
1608
1609 void write_(const void *buf, size_t size, size_t offset=0) override final
1610 {
1611 assert(isWritable());
1612 auto &post_write_noti = getPostWriteNotificationSource();
1613
1614 if (SPARTA_EXPECT_FALSE(post_write_noti.observed())) {
1615 prior_val_dview_ = dview_;
1616 poke_(buf, size, offset);
1617 post_write_noti.postNotification(post_write_noti_data_);
1618 } else {
1619 poke_(buf, size, offset);
1620 }
1621 }
1622
1623 void poke_(const void *buf, size_t size, size_t offset=0) override final
1624 {
1625 assert(isWritable());
1626 dview_.getLine()->write(
1627 dview_.getOffset() + offset, size, static_cast<const uint8_t *>(buf));
1628 }
1629
1630 void dmiWrite_(const void *buf, size_t size, size_t offset = 0) override final
1631 {
1632 assert(isWritable());
1633 dmiWriteImpl_(buf, size, offset);
1634 }
1635
1636 inline void dmiReadImpl_(void *buf, size_t size, size_t offset = 0) const
1637 {
1638 memcpy(buf, raw_data_ptr_ + offset, size);
1639 }
1640
1641 inline void dmiWriteImpl_(const void *buf, size_t size, size_t offset = 0)
1642 {
1643 assert(isWritable());
1644 memcpy(raw_data_ptr_ + offset, buf, size);
1645 dview_.getLine()->flagDirty();
1646 }
1647
1651 DataView dview_;
1652
1657 DataView prior_val_dview_;
1658
1662 PostWriteNotiSrc::data_type post_write_noti_data_;
1663
1667 ReadNotiSrc::data_type post_read_noti_data_;
1668
1672 uint8_t *raw_data_ptr_ = nullptr;
1673};
1674
1675} // namespace sparta
1676
1677
1679inline std::ostream& operator<<(std::ostream& o, const sparta::Register& reg){
1680 o << reg.stringize();
1681 return o;
1682}
1683
1685inline std::ostream& operator<<(std::ostream& o, const sparta::Register* reg){
1686 if(reg == 0){
1687 o << "null";
1688 }else{
1689 o << reg->stringize();
1690 }
1691 return o;
1692}
1693
1694
1696inline std::ostream& operator<<(std::ostream& o, const sparta::Register::Field& field){
1697 o << field.stringize();
1698 return o;
1699}
1700
1702inline std::ostream& operator<<(std::ostream& o, const sparta::Register::Field* field){
1703 if(field == 0){
1704 o << "null";
1705 }else{
1706 o << field->stringize();
1707 }
1708 return o;
1709}
1710
1711
1713#define SPARTA_REGISTER_BODY \
1714 const sparta::RegisterBase::Definition sparta::RegisterBase::DEFINITION_END{0, nullptr, 0, nullptr, 0, nullptr, 0, { }, { }, nullptr, 0, 0, 0, 0, 0};
Set of macros for Sparta assertions. Caught by the framework.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
#define SPARTA_EXPECT_FALSE(x)
A macro for hinting to the compiler a particular condition should be considered most likely false.
Exception class for all of Sparta.
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.
ArchData::Line * getLine() const
Get already-placed line.
Definition DataView.hpp:107
offset_type getOffset() const
Definition DataView.hpp:104
ArchData * getArchData() const
Definition DataView.hpp:98
static const std::string DATAVIEW_UNPLACED_STR
String to show instead of a value when representing an unplaced dataview.
Definition DataView.hpp:39
ArchDataSegment::ident_type ident_type
DataView identifiers (distinguishes views in the same ArchData)
Definition DataView.hpp:32
ArchDataSegment::offset_type offset_type
Represents offset into ArchData.
Definition DataView.hpp:31
uint32_t index_type
Type used for specifying index into this DataView during a read or write.
Definition DataView.hpp:33
A TreeNode that generates a specific type of notification which propagates up a tree of TreeNodes (us...
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:137
size_type getNumBits() const
Gets number of bits in this field.
Definition Register.hpp:342
void write(access_type t)
Write the field.
Definition Register.hpp:288
const Definition & getDefinition() const
Gets the Definition with which this Field was constructed.
Definition Register.hpp:350
access_type peek() const
Peeks the field.
Definition Register.hpp:277
size_type getHighBit() const
Returns the index of the high bit (inclusive) in this field.
Definition Register.hpp:332
virtual std::string stringize(bool pretty=false) const override
Create a string representation of this node.
Definition Register.hpp:358
static const size_type MAX_FIELD_BITS
Maximum number of bits allowed in a field.
Definition Register.hpp:162
uint64_t access_type
Type used for bitfield access.
Definition Register.hpp:157
void pokeUnmasked(access_type t)
Poke the field without any read-only mask being applied.
Definition Register.hpp:308
Field(RegisterBase &reg, const Definition &def)
Field Constructor.
Definition Register.hpp:216
access_type read()
Read the field.
Definition Register.hpp:267
bool isReadOnly() const
Returns true if this field is marked read-only.
Definition Register.hpp:337
size_type getLowBit() const
Returns the index of the low bit (inclusive) in this field.
Definition Register.hpp:325
void poke(access_type t)
Poke the field.
Definition Register.hpp:300
Base class to represents an architected register of any size that is a power of 2 and greater than 0 ...
Definition Register.hpp:64
size_type getNumBits() const
Gets the size of this register's value in bits.
Definition Register.hpp:878
uint32_t group_num_type
Numeric group identifier for register lookup.
Definition Register.hpp:88
group_num_type getGroupNum() const
Gets the group number of this register as specified in its definition.
Definition Register.hpp:852
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:722
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:936
static constexpr ident_type INVALID_ID
Represents an invalid Register ID.
Definition Register.hpp:687
T read(index_type idx=0)
Read a value from this register.
Definition Register.hpp:982
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:830
void reset(bool unmasked=true)
Reset this register to its default value.
Definition Register.hpp:804
std::function< bool(RegisterBase *, uint64_t)> register_write_callback_type
Register write callback.
Definition Register.hpp:119
const FieldVector & getFields() const
Const qualified version of getFields.
Definition Register.hpp:927
TreeNode::group_idx_type group_idx_type
TreeNode group index.
Definition Register.hpp:93
NotificationSource< ReadAccess > ReadNotiSrc
Notification type for Register read accesses.
Definition Register.hpp:475
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:959
bool hasReadCB() const
Returns true if register has a read callback; false otherwise.
void poke(T val, index_type idx=0)
Poke a value into this regster.
void addWriteCB(register_write_callback_type callback)
Registers a callback for writing a 32- or 64-bit register value.
std::string getValueAsByteString() const
Creates a string representing this register's value as a sequence of bytes, separated by a spaces,...
std::function< sparta::utils::ValidValue< uint64_t >(RegisterBase *)> register_read_callback_type
Register read callback.
Definition Register.hpp:114
sparta::utils::ValidValue< uint64_t > readWithCheck()
Read a value from this register, possibly via a user-supplied callback.
Definition Register.hpp:992
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:128
T dmiRead(index_type idx=0) const
Read value directly from the Register's backing store.
PostWriteNotiSrc & getPostWriteNotificationSource()
Returns the post-write notification-source node for this register which can be used to observe writes...
DataView::ident_type ident_type
Identifier to distinguish from other registers in the same RegisterSet.
Definition Register.hpp:73
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:900
virtual ~RegisterBase()
Destructor.
Definition Register.hpp:793
std::vector< Field * > FieldVector
Vector of Register Fields.
Definition Register.hpp:109
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:947
friend class Field
Allow Fields to access register internals (e.g. dview_)
Definition Register.hpp:696
void pokeUnmasked(T val, index_type idx=0)
Poke a value into this regster without it being affected by the write-mask.
std::string getWriteMaskAsBitString() const
Creats a string representing this register's write-mask as sequence of bits, separated by a space bet...
size_type getNumFields() const
Gets the number of fields within this register.
Definition Register.hpp:883
DataView::offset_type size_type
Size of register and bit or byte offset within register data.
Definition Register.hpp:83
Definition::HintsT getHintFlags() const
Returns the hint flags for this type.
Definition Register.hpp:953
size_type getNumBytes() const
Gets the size of this register's value in bytes.
Definition Register.hpp:873
NotificationSource< PostWriteAccess > PostWriteNotiSrc
Notification type for Register write accesses.
Definition Register.hpp:515
void writeUnmasked(T val, index_type idx=0)
Write a value into this register without it being affected by the write-mask.
std::vector< const char * > AliasVector
Vector of Register Aliases.
Definition Register.hpp:104
uint32_t bank_idx_type
Numeric bank identifier for bank lookup.
Definition Register.hpp:99
static const Definition DEFINITION_END
Entry indicating the end of a sparta::Register::Definition array.
Definition Register.hpp:693
const Definition & getDefinition() const
Gets the definition supplied during the construciton of this Register.
Definition Register.hpp:967
group_idx_type getGroupIdx() const
Gets the group index of this register as specified in its definition.
Definition Register.hpp:868
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:846
static constexpr group_num_type GROUP_NUM_NONE
Represents no group much like sparta::TreeNode::GROUP_NAME_NONE.
Definition Register.hpp:690
FieldVector & getFields()
Gets the full set of register fields.
Definition Register.hpp:922
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:859
DataView::index_type index_type
Index of read/write access within register.
Definition Register.hpp:78
virtual void onAddingChild_(TreeNode *child) override
React to child registration.
bool isBanked() const
Is this register banked.
Definition Register.hpp:915
bool writeWithCheck(T val)
Write a value to this register, possibly via a user-supplied callback.
uint32_t getSize() const
Get the number of bytes.
void set(const DataT &masked_bits)
Set the given masked_bits in this RegisterBits instance.
const uint8_t * data() const
Get the internal data pointer.
An implementation of a RegisterBase.
RegisterBase::index_type index_type
Index of read/write access within register.
std::string stringize(bool pretty=false) const override
Create a string representation of this node.
T dmiRead(index_type idx=0) const
Read value directly from the Register's backing store.
void dmiWrite(T val, index_type idx=0)
Write a value directly to this Register's backing store.
void writeUnmasked(T val, index_type idx=0)
Write a value into this register without it being affected by the write-mask.
Used to construct and throw a standard C++ exception. Inherits from std::exception.
Node in a composite tree representing a sparta Tree item.
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 ConstT getChildAs(const std::string &name, bool must_exist=true) const
Retrieves a child that is castable to T with the given dotted path.
const std::string & getName() const override
Gets the name of this node.
void setExpectedParent_(const TreeNode *parent)
Tracks a node as an expected parent without actually adding this node as a child. This is used almost...
Provides a wrapper around a value to ensure that the value is assigned.
Macros for handling exponential backoff.
std::ostream & operator<<(std::ostream &o, const SimulationInfo &info)
ostream insertion operator for SimulationInfo
bool isPowerOf2(uint64_t x)
Determines if input is 0 or a power of 2.
Definition Utils.hpp:142
Describes an architected Register.
Definition Register.hpp:549
const ident_type id
ID. Must be unique within a register set.
Definition Register.hpp:553
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:574
uint16_t RegDomainT
Register Domain. The flags are not part of sparta but should be defined by the model.
Definition Register.hpp:677
const char * name
String identifier for this register which distinguishes it from its neighbors. Must adhere to TreeNod...
Definition Register.hpp:560
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:659
const char * desc
Description. Must NOT be NULL.
Definition Register.hpp:597
const ident_type subset_of
ID of register of which this is a subset. If INVALID_ID, has no effect.
Definition Register.hpp:651
const unsigned char * initial_value
Initial value of this register.
Definition Register.hpp:664
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:645
const size_type bytes
Size of this register in bytes. Non-byte multiples are not supported.
Definition Register.hpp:603
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:584
const bool writable
Writable flag, taken from the register definition.
Definition Register.hpp:683
const group_idx_type group_idx
Index of register within group. See sparta::TreeNode::TreeNode. Internally, a lookup-vector is built ...
Definition Register.hpp:592
const std::vector< bank_idx_type > bank_membership
Vector of bank indexes of banks in which this register is accessible.
Definition Register.hpp:639
const std::vector< Field::Definition > fields
Vector of field definitions. Use like so for empty fields: { name, group_num,..., bytes,...
Definition Register.hpp:611
uint16_t HintsT
Register hint flags. The flags are not part of sparta but should be defined by the model.
Definition Register.hpp:670
Field Definition structure.
Definition Register.hpp:169
size_type high_bit
High bit (inclusive). Must be >= low_bit. (high_bit-low_bit) must be < MAX_FIELD_BITS....
Definition Register.hpp:205
size_type low_bit
Low bit (inclusive)
Definition Register.hpp:204
Definition()=delete
Allow default constructor.
bool read_only
Is this a read-only field.
Definition Register.hpp:206
const char * name
Name - Must ahere to TreeNode::validateName. Must not be NULL.
Definition Register.hpp:202
Definition(const char *_name, const char *_desc, size_type _low_bit, size_type _high_bit)
Limited constructor for backward compatibility.
Definition Register.hpp:179
const char * desc
Description. Must NOT be NULL.
Definition Register.hpp:203
Structure containing data for a Register post-write notification.
Definition Register.hpp:484
const RegisterBase *const reg
Register on which the write access took place.
Definition Register.hpp:497
const DataView *const prior
Value of reg prior to this write.
Definition Register.hpp:502
Structure containing data for a Register pre- or post-read notification.
Definition Register.hpp:452
const DataView *const value
Value just read from reg. This value can also be retrieved through reg.
Definition Register.hpp:469
const RegisterBase *const reg
Register on which the read access took place.
Definition Register.hpp:463