C++ Device API Reference Manual
Reference documentation for the Simics C++ Device API.
 
Loading...
Searching...
No Matches
register.h
Go to the documentation of this file.
1// -*- mode: C++; c-file-style: "virtutech-c++" -*-
2
3/*
4 © 2022 Intel Corporation
5
6 This software and the related documents are Intel copyrighted materials, and
7 your use of them is governed by the express license under which they were
8 provided to you ("License"). Unless the License provides otherwise, you may
9 not use, modify, copy, publish, distribute, disclose or transmit this software
10 or the related documents without Intel's prior written permission.
11
12 This software and the related documents are provided as is, with no express or
13 implied warranties, other than those that are expressly stated in the License.
14*/
15
16#ifndef SIMICS_REGISTER_H
17#define SIMICS_REGISTER_H
18
19#include <simics/base/conf-object.h> // SIM_object_class
20#include <simics/base/notifier.h> // SIM_notify
21#include <simics/simulator/conf-object.h> // SIM_class_has_attribute
22#include <string>
23#include <vector>
24#include <map>
25#include <memory>
26#include <utility>
27#include <limits>
28#include <algorithm>
29#include <exception>
30#include <iomanip>
31#include <set>
32
33#include "conf-class.h" // expand_names
34#include "attribute-traits.h"
35#include "field.h"
36#include "hierarchical-object.h"
40
41namespace simics {
42
43// @return the first bit of one found from bit 0 of bits
44static unsigned find_first(const std::bitset<64> &bits) {
45 unsigned idx = 0;
46 while (idx < 64 && !bits[idx]) {
47 ++idx;
48 }
49 return idx;
50}
51
52extern std::pair<size_t, size_t> overlap_range(size_t r1_start,
53 size_t r1_end,
54 size_t r2_start,
55 size_t r2_end);
56
57/*
58 * A register with default behavior
59 *
60 * A register consists of several bytes from a bank. The default
61 * behavior is all bits support both read and write without any side effects.
62 */
63// coverity[rule_of_five_violation:FALSE]
65 public HierarchicalObject {
66 public:
67 // @param name begins with the bank name, e.g, "bankA.registerB"
70
71 Register(BankInterface *parent, std::string_view reg_name)
73 parent->dev_obj(),
74 std::string(parent->name()) + SEPARATOR + reg_name.data(),
75 this),
76 parent_(parent) {}
77
78 // No duplication
79 Register(const Register&) = delete;
80 Register& operator=(const Register&) = delete;
81
83 : HierarchicalObject(std::move(rhs)),
84 init_val_(rhs.init_val_),
85 byte_mask_(rhs.byte_mask_),
86 byte_pointers_(std::move(rhs.byte_pointers_)),
87 fields_(std::move(rhs.fields_)),
88 allocated_fields_(std::move(rhs.allocated_fields_)) {
90 }
92 // check for self-assignment
93 if (this == &rhs)
94 return *this;
95
96 HierarchicalObject::operator=(std::move(rhs));
98 init_val_ = rhs.init_val_;
99 byte_mask_ = rhs.byte_mask_;
100 byte_pointers_ = std::move(rhs.byte_pointers_);
101 fields_ = std::move(rhs.fields_);
102 allocated_fields_ = std::move(rhs.allocated_fields_);
103 return *this;
104 }
105
106 friend std::ostream& operator<< (std::ostream& stream,
107 const Register& reg) {
108 stream << "0x" << std::setfill('0')
109 << std::setw(reg.number_of_bytes() * 2)
110 << std::hex << reg.get();
111 return stream;
112 }
113
114 std::string_view name() const override {
116 }
117
118 const std::string &hierarchical_name() const override {
120 }
121
122 const std::string &description() const override {
124 }
125
126 MappableConfObject *dev_obj() const override {
128 }
129
130 ConfObjectRef bank_obj_ref() const override {
132 }
133
134 unsigned number_of_bytes() const override {
135 return byte_pointers_.size();
136 }
137
138 void init(std::string_view desc, unsigned number_of_bytes,
139 uint64_t init_val) override {
140 set_description(desc);
141 check_number_of_bytes(number_of_bytes);
142 set_init_value(init_val);
143 set(init_val_);
144 if (parent_ == nullptr) {
145 parent_ = dev_obj()->get_iface<BankInterface>(
146 std::string(parent_name()));
147 }
148 // Add attribute for both mapped and unmapped registers
149 add_register_as_simics_attribute(this);
150 }
151
152 void reset() override {
153 set(init_val_);
154 }
155
156 bool is_read_only() const override {
157 return false;
158 }
159
160 bool is_mapped() const override {
161 return true;
162 }
163
164 void set_byte_pointers(const register_memory_t &byte_pointers) override {
165 if (!byte_pointers_.empty()) {
166 SIM_LOG_SPEC_VIOLATION(
167 1, bank_obj_ref(), 0,
168 "Cannot reset the register byte pointers, ignored");
169 return;
170 }
171 if (byte_pointers.size() > 8 || byte_pointers.empty()) {
172 SIM_LOG_ERROR(
173 bank_obj_ref(), 0,
174 "The supported register size is [1-8] bytes");
175 return;
176 }
177
178 std::set<register_memory_t::value_type> unique_pointers(
179 byte_pointers.begin(), byte_pointers.end());
180 if (byte_pointers.size() != unique_pointers.size()) {
181 SIM_LOG_ERROR(
182 bank_obj_ref(), 0,
183 "The byte_pointers contains duplicate items");
184 return;
185 }
186
187 // Shallow copy is OK since the pointers are intended to be shared
188 byte_pointers_ = byte_pointers;
189
190 byte_mask_ = std::numeric_limits<uint64_t>::max();
191 byte_mask_ >>= (8 - number_of_bytes()) * 8;
192 }
193
194 uint64_t get() const override {
195 uint64_t value = read_from_byte_pointers();
196 if (fields_.empty()) {
197 return value;
198 }
199
200 auto num_bytes = number_of_bytes();
201 // Pass to field.get
202 for (const auto &[offset, f] : fields_) {
203 size_t bits_mask = byte_mask_;
204 if (f->number_of_bits() != num_bytes * 8) {
205 bits_mask = (1ULL << f->number_of_bits()) - 1;
206 }
207 value &= ~(bits_mask << offset);
208 value |= (f->get() & bits_mask) << offset;
209 }
210 return value;
211 }
212
213 void set(uint64_t value) override {
214 auto v = value & byte_mask_;
215 bool changed = false;
216 for (const auto byte_pointer : byte_pointers_) {
217 if (*byte_pointer != (v & 0xff)) {
218 changed = true;
219 *byte_pointer = v & 0xff;
220 }
221 v = v >> 8;
222 }
223
224 auto num_bytes = number_of_bytes();
225 for (const auto &[offset, f] : fields_) {
226 size_t bits_mask = byte_mask_;
227 if (f->number_of_bits() != num_bytes * 8) {
228 bits_mask = (1ULL << f->number_of_bits()) - 1;
229 }
230 f->set((value >> offset) & bits_mask);
231 }
232 if (changed) {
233 SIM_notify(bank_obj_ref(), Sim_Notify_Bank_Register_Value_Change);
234 }
235 }
236
237 uint64_t read(uint64_t enabled_bits) override {
238 enabled_bits &= byte_mask_;
239 if (enabled_bits == 0) {
240 return 0;
241 }
242
243 std::bitset<64> bits = enabled_bits;
244 unsigned start_bit_offset = find_first(bits);
245 size_t size = bits.count();
246 unsigned end_bit_offset = start_bit_offset + size;
247 if (end_bit_offset != 64 && enabled_bits >> end_bit_offset != 0) {
249 fmt::format("enabled_bits({:#x}) is malformed:"
250 " does not contain consecutive ones",
251 enabled_bits));
252 return 0;
253 }
254
255 bool partial = enabled_bits != byte_mask_;
256 uint64_t ret = 0;
257 if (fields_.empty()) {
258 ret = get() & enabled_bits;
259 } else {
260 bits &= read_from_byte_pointers();
261
262 // The first_field points to the first item in the map with a key
263 // less than or equal to offset
264 auto first_field = fields_.upper_bound(start_bit_offset);
265 if (first_field != fields_.begin()) {
266 --first_field;
267 }
268
269 for (auto it = first_field;
270 it != fields_.end() && it->first < end_bit_offset; ++it) {
271 auto[field_offset, field_iface] = *it;
272 size_t field_size = field_iface->number_of_bits();
273 size_t field_end_range = field_offset + field_size;
274 auto[overlap_start, overlap_end] = overlap_range(
275 start_bit_offset, end_bit_offset,
276 field_offset, field_end_range);
277 size_t bits_to_read = overlap_end - overlap_start;
278
279 // Field has no overlap with the access
280 if (bits_to_read == 0) {
281 continue;
282 }
283
284 uint64_t bits_mask = std::numeric_limits<uint64_t>::max();
285 unsigned bits_shift = overlap_start - field_offset;
286 if (bits_to_read < 64)
287 bits_mask = (1ULL << bits_to_read) - 1;
288 bits_mask <<= bits_shift;
289
290 uint64_t field_val = field_iface->read(bits_mask) & bits_mask;
291 field_val >>= bits_shift;
292
293 for (unsigned index = 0; index < bits_to_read; ++index) {
294 bits[index + overlap_start] = (field_val >> index) & 1;
295 }
296 }
297
298 ret = bits.to_ullong();
299 }
300
301 if (partial) {
302 if (start_bit_offset % 8 == 0 && end_bit_offset % 8 == 0) {
304 fmt::format("Partial read from register {}:"
305 " bytes {}-{} -> {:#x}", name(),
306 start_bit_offset / 8,
307 end_bit_offset / 8 - 1, ret));
308 } else {
310 fmt::format("Partial read from register {}:"
311 " bits {}-{} -> {:#x}", name(),
312 start_bit_offset,
313 end_bit_offset - 1, ret));
314 }
315 } else {
317 fmt::format("Read from register {} -> {:#x}",
318 name(), ret));
319 }
320
321 return ret;
322 }
323
324 void write(uint64_t value, uint64_t enabled_bits) override {
325 enabled_bits &= byte_mask_;
326 if (enabled_bits == 0) {
327 return;
328 }
329
330 std::bitset<64> bits = enabled_bits;
331 unsigned start_bit_offset = find_first(bits);
332 size_t number_of_bits = bits.count();
333 unsigned end_bit_offset = start_bit_offset + number_of_bits;
334 if (end_bit_offset != 64 && enabled_bits >> end_bit_offset != 0) {
336 fmt::format("enabled_bits({:#x}) is malformed:"
337 " does not contain consecutive ones",
338 enabled_bits));
339 return;
340 }
341 if (enabled_bits != byte_mask_) {
342 if (start_bit_offset % 8 == 0 && end_bit_offset % 8 == 0) {
344 fmt::format("Partial write to register {}:"
345 " bytes {}-{} <- {:#x}", name(),
346 start_bit_offset / 8,
347 end_bit_offset / 8 - 1,
348 value & enabled_bits));
349 } else {
351 fmt::format("Partial write to register {}:"
352 " bits {}-{} <- {:#x}", name(),
353 start_bit_offset,
354 end_bit_offset - 1,
355 value & enabled_bits));
356 }
357 } else {
359 fmt::format("Write to register {} <- {:#x}",
360 name(), value & enabled_bits));
361 }
362
363 if (fields_.empty()) {
364 set((get() & ~enabled_bits) | (value & enabled_bits));
365 return;
366 }
367
368 // The first_field points to the first item in the map with a key
369 // less than or equal to offset
370 auto first_field = fields_.upper_bound(start_bit_offset);
371 if (first_field != fields_.begin()) {
372 --first_field;
373 }
374
375 for (auto it = first_field;
376 it != fields_.end() && it->first < end_bit_offset; ++it) {
377 auto[field_offset, field_iface] = *it;
378 size_t field_size = field_iface->number_of_bits();
379 size_t field_end_range = field_offset + field_size;
380 auto[overlap_start, overlap_end] = overlap_range(
381 start_bit_offset, end_bit_offset,
382 field_offset, field_end_range);
383 size_t bits_to_write = overlap_end - overlap_start;
384
385 // Field has no overlap with the access
386 if (bits_to_write == 0) {
387 continue;
388 }
389
390 uint64_t bits_mask = std::numeric_limits<uint64_t>::max();
391 if (bits_to_write < 64)
392 bits_mask = (1ULL << bits_to_write) - 1;
393
394 auto write_value = (value >> overlap_start) & bits_mask;
395 unsigned bits_shift = overlap_start - field_offset;
396 write_value <<= bits_shift;
397 bits_mask <<= bits_shift;
398
399 field_iface->write(write_value, bits_mask);
400 }
401 }
402
403 /*
404 * Parse the field information, add the field or field array into
405 * the resource map
406 */
407 void parse_field(const field_t &f) override {
408 if (dev_obj()->finalized()) {
410 fmt::format("Cannot add fields for register ({})"
411 " when device has finalized",
413 return;
414 }
415
416 const auto &[name, desc, offset, width] = f;
417
418 if (width == 0) {
419 SIM_LOG_ERROR(bank_obj_ref(), 0,
420 "Ignored invalid field as the width is 0");
421 return;
422 }
423
424 if (name.array_str().empty()) {
425 add_field(name, desc, offset, width);
426 } else {
427 for (const auto &[_name, _offset]
428 : name.arrayNamesToOffsets(width)) {
429 add_field(_name, desc, offset + _offset, width);
430 }
431 }
432 }
433
434 std::vector<field_t> fields_info() const override {
435 std::vector<field_t> info;
436 for (auto const &field : fields_) {
437 info.emplace_back(field.second->name().data(),
438 field.second->description(),
439 field.first,
440 field.second->number_of_bits());
441 }
442 return info;
443 }
444
445 BankInterface *parent() const override {
446 return parent_;
447 }
448
449 protected:
450 // Set the initial value of the register
451 void set_init_value(uint64_t init_val) {
452 init_val_ = init_val;
453 }
454
455 private:
456 static void add_register_as_simics_attribute(
457 const RegisterInterface *iface) {
458 auto *bank_class = SIM_object_class(iface->bank_obj_ref());
459
460 auto reg_name = iface->name();
461 // Extract the name before the '[' character from the input
462 // string_view. Since later code relies on null-terminated
463 // strings (using data()), we use std::string instead of
464 // std::string_view to ensure the extracted name is
465 // null-terminated.
466 std::string reg_name_wo_brackets {
467 reg_name.substr(0, reg_name.find('['))
468 };
469
470 if (SIM_class_has_attribute(bank_class,
471 reg_name_wo_brackets.c_str())) {
472 return;
473 }
474
475 std::string type {"i"};
476 auto dims = std::count(reg_name.begin(), reg_name.end(), '[');
477 for (int index = 0; index < dims; ++index) {
478 type = '[' + type + "+]";
479 }
480 auto hashed = MapNameToInterfaceObject<
481 RegisterInterface>::hash_str(iface->hierarchical_name());
482 SIM_register_attribute_with_user_data(
483 bank_class, reg_name_wo_brackets.c_str(),
484 get_reg, reinterpret_cast<void *>(hashed),
485 set_reg, reinterpret_cast<void *>(hashed),
486 Sim_Attr_Optional, type.c_str(),
487 iface->description().c_str());
488 }
489
490 static attr_value_t get_reg_array(int indices, int dim_index,
491 MappableConfObject *obj,
492 const std::string &base_name) {
493 size_t array_index = 0;
494 if (dim_index == indices) {
495 // The most inner dimension
496 std::vector<size_t> values;
497 while (true) {
498 auto *reg_iface = obj->template get_iface<
499 RegisterInterface>(
500 base_name + '[' + std::to_string(array_index) \
501 + ']');
502 if (reg_iface == nullptr) {
503 break;
504 }
505 values.push_back(reg_iface->get());
506 ++array_index;
507 }
508 if (values.empty()) {
509 return SIM_make_attr_nil();
510 } else {
511 return std_to_attr(values);
512 }
513 } else {
514 std::vector<attr_value_t> values;
515 while (true) {
516 auto attr = get_reg_array(indices, dim_index + 1, obj,
517 fmt::format("{}[{}]", base_name,
518 array_index++));
519 if (SIM_attr_is_nil(attr)) {
520 break;
521 } else {
522 values.push_back(attr);
523 }
524 }
525 return std_to_attr(values);
526 }
527 }
528
529 static attr_value_t get_reg(conf_object_t *obj, void *data) {
530 auto *mappable_obj = from_obj<MappableConfObject>(
531 SIM_port_object_parent(obj));
532 auto name_hash = reinterpret_cast<size_t>(data);
533 auto *reg_iface = mappable_obj->get_iface(name_hash);
534 if (reg_iface == nullptr) {
535 SIM_c_attribute_error("register not found");
536 return SIM_make_attr_nil();
537 }
538
539 auto reg_name = reg_iface->name();
540 auto indices = std::count(reg_name.cbegin(),
541 reg_name.cend(), '[');
542 if (indices == 0) {
543 return std_to_attr(reg_iface->get());
544 }
545
546 // This register contains an array but size unknown
547 auto base_name = std::string(reg_iface->parent()->name()) + SEPARATOR \
548 + std::string(reg_name.substr(0, reg_name.find('[')));
549 return get_reg_array(indices, 1, mappable_obj, base_name);
550 }
551
552 static set_error_t set_reg_array(int indices, int dim_index,
553 MappableConfObject *obj,
554 const std::string &base_name,
555 attr_value_t *val) {
556 size_t array_index = 0;
557 if (dim_index == indices) {
558 // The most inner dimension
559 auto values = attr_to_std<std::vector<size_t>>(*val);
560 while (true) {
561 auto *reg_iface = obj->template get_iface<
562 RegisterInterface>(
563 base_name + '[' + std::to_string(array_index) \
564 + ']');
565 if (reg_iface == nullptr) {
566 break;
567 } else if (array_index == values.size()) {
568 return Sim_Set_Illegal_Index;
569 }
570 reg_iface->set(values.at(array_index));
571 ++array_index;
572 }
573 if (values.size() == array_index) {
574 return Sim_Set_Ok;
575 } else {
576 return Sim_Set_Illegal_Index;
577 }
578 } else {
579 auto values = attr_to_std<std::vector<attr_value_t>>(*val);
580 while (array_index < values.size()) {
581 auto status = set_reg_array(indices, dim_index + 1, obj,
582 fmt::format("{}[{}]", base_name,
584 &values.at(array_index));
585 if (status == Sim_Set_Illegal_Index) {
586 if (array_index + 1 == values.size()) {
587 return Sim_Set_Ok;
588 } else {
589 return Sim_Set_Illegal_Index;
590 }
591 }
592 ++array_index;
593 }
594 return Sim_Set_Ok;
595 }
596 }
597
598 static set_error_t set_reg(conf_object_t *obj, attr_value_t *val,
599 void *data) {
600 auto *mappable_obj = from_obj<MappableConfObject>(
601 SIM_port_object_parent(obj));
602 auto name_hash = reinterpret_cast<size_t>(data);
603 auto reg_iface = mappable_obj->get_iface(name_hash);
604 if (!reg_iface) {
605 return Sim_Set_Interface_Not_Found;
606 }
607
608 auto reg_name = reg_iface->name();
609 auto indices = std::count(reg_name.cbegin(),
610 reg_name.cend(), '[');
611 if (indices == 0) {
612 reg_iface->set(attr_to_std<size_t>(*val));
613 return Sim_Set_Ok;
614 }
615
616 // This register contains an array but size unknown
617 auto base_name = std::string(reg_iface->parent()->name()) + SEPARATOR \
618 + std::string(reg_name.substr(0, reg_name.find('[')));
619 return set_reg_array(indices, 1, mappable_obj, base_name, val);
620 }
621
622 // Check the number_of_bytes from init method is valid
623 void check_number_of_bytes(unsigned number_of_bytes) {
624 if (number_of_bytes > 8 || number_of_bytes == 0) {
625 SIM_LOG_ERROR(bank_obj_ref(), 0,
626 "The supported register size is [1-8] bytes");
627 return;
628 }
629 if (byte_pointers_.size() != number_of_bytes) {
631 fmt::format("The memory size({}) does not fit "
632 "the number of bytes({})",
633 byte_pointers_.size(),
635 return;
636 }
637 }
638
639 // Return if the input range overlaps with the existing field range
640 bool has_range_overlap(size_t lsb, size_t msb) const {
641 return std::any_of(fields_.cbegin(), fields_.cend(),
642 [lsb, msb](auto p){
643 return lsb < (p.first + p.second->number_of_bits())
644 && p.first < msb;
645 });
646 }
647
648 // Add a single field into the resource map
649 void add_field(std::string_view field_name, std::string_view desc,
650 Offset offset, BitWidth width) {
651 if (offset >= number_of_bytes() * 8
652 || offset + width > number_of_bytes() * 8) {
653 SIM_LOG_ERROR(bank_obj_ref(), 0,
654 "Ignored invalid field as the offset exceeds"
655 " the number of bits");
656 return;
657 }
658
659 if (has_range_overlap(offset, offset + width - 1)) {
660 SIM_LOG_ERROR(bank_obj_ref(), 0,
661 "Ignored invalid field as it overlaps with"
662 " other field");
663 return;
664 }
665
666 const std::string full_name {
667 hierarchical_name() + SEPARATOR + field_name.data()};
668 fields_[offset] = dev_obj()->get_iface<FieldInterface>(full_name);
669 if (fields_[offset] == nullptr) {
670 allocated_fields_.push_back(
671 std::unique_ptr<FieldInterface>(
672 new Field(dev_obj(), full_name)));
673 fields_[offset] = allocated_fields_.back().get();
675 fmt::format("Created default field for {}",
676 full_name));
677 } else if (fields_[offset]->number_of_bits() == 0) {
679 fmt::format("Used user defined field for {}",
680 full_name));
681 } else {
682 fields_.erase(offset);
684 fmt::format("Duplicated field name({}) on same"
685 " register", field_name));
686 return;
687 }
688
689 if (byte_pointers_.empty()) {
691 fmt::format("No storage allocated on register %s",
692 name()));
693 return;
694 }
695
696 // Pass the related bits to the field in format of byte
697 // pointer with a mask
698 bits_type bits;
699 for (unsigned i = offset / 8; i <= (offset + width - 1) / 8; ++i) {
700 uint8_t bits_mask = 0xff;
701 if (i == offset / 8) {
702 // The first byte
703 bits_mask <<= (offset % 8);
704 }
705 if (i == (offset + width - 1) / 8) {
706 // The last byte
707 uint8_t num_masked_bits = (offset + width) % 8;
708 if (num_masked_bits != 0) {
709 bits_mask &= (1 << num_masked_bits) - 1;
710 }
711 }
712 bits.push_back(std::make_pair(byte_pointers_[i], bits_mask));
713 }
714 fields_[offset]->init(desc, bits, offset);
715 }
716
717 uint64_t read_from_byte_pointers() const {
718 uint64_t result = 0;
719 auto num_bytes = number_of_bytes();
720 for (unsigned i = 0; i < num_bytes; ++i) {
721 result |= (uint64_t)(*byte_pointers_[i]) << (8 * i);
722 }
723 return result;
724 }
725
726 // The initial value after the register is created
727 uint64_t init_val_ {0};
728 // Used to mask the valid bytes when reading/writing the register
729 uint64_t byte_mask_ {std::numeric_limits<uint64_t>::max()};
730 // first bit of the bitset corresponds to the least significant digit
731 // of the number and the last bit corresponds to the most significant digit
732 // i.e. Little-endian byte & bit order
733 register_memory_t byte_pointers_;
734 // The fields mapped on the register. Ordered by the lsb.
735 std::map<size_t, FieldInterface *> fields_;
736 // The parent interface
737 BankInterface *parent_ {nullptr};
738 // @internal: tracks the allocated fields
739 std::vector<std::unique_ptr<FieldInterface>> allocated_fields_;
740};
741
742} // namespace simics
743
744#endif
struct conf_object conf_object_t
Definition: bank-issue-callbacks-interface.h:23
Definition: bank-interface.h:45
Represents Simics C type conf_object_t.
Definition: conf-object.h:37
Definition: hierarchical-object.h:43
static const uint64_t Register_Read
Log group ID for Register_Read and Register_Write is fixed.
Definition: hierarchical-object.h:340
void init_iface(BankInterface *iface)
Definition: hierarchical-object.h:113
HierarchicalObject & operator=(const HierarchicalObject &)=delete
static const uint64_t Register_Write
Definition: hierarchical-object.h:341
ConfObjectRef bank_obj_ref() const override
Definition: hierarchical-object.h:181
std::string_view name() const override
Definition: hierarchical-object.h:147
std::string_view parent_name() const override
Definition: hierarchical-object.h:191
const std::string & description() const override
Definition: hierarchical-object.h:156
void set_description(std::string_view desc) override
Definition: hierarchical-object.h:160
MappableConfObject * dev_obj() const override
Definition: hierarchical-object.h:177
const std::string & hierarchical_name() const override
Definition: hierarchical-object.h:143
Definition: mappable-conf-object.h:131
IFACE * get_iface(const std::string &name) const
Definition: mappable-conf-object.h:170
Definition: register-interface.h:36
virtual const std::string & description() const =0
virtual const std::string & hierarchical_name() const =0
virtual std::string_view name() const =0
virtual ConfObjectRef bank_obj_ref() const =0
Definition: register.h:65
const std::string & hierarchical_name() const override
Definition: register.h:118
bool is_read_only() const override
Definition: register.h:156
Register(const Register &)=delete
void set(uint64_t value) override
Definition: register.h:213
void write(uint64_t value, uint64_t enabled_bits) override
Definition: register.h:324
void set_byte_pointers(const register_memory_t &byte_pointers) override
Definition: register.h:164
std::string_view name() const override
Definition: register.h:114
void init(std::string_view desc, unsigned number_of_bytes, uint64_t init_val) override
Definition: register.h:138
Register(BankInterface *parent, std::string_view reg_name)
Definition: register.h:71
void set_init_value(uint64_t init_val)
Definition: register.h:451
ConfObjectRef bank_obj_ref() const override
Definition: register.h:130
Register & operator=(const Register &)=delete
bool is_mapped() const override
Definition: register.h:160
Register(MappableConfObject *dev_obj, const std::string &name)
Definition: register.h:68
const std::string & description() const override
Definition: register.h:122
std::vector< field_t > fields_info() const override
Definition: register.h:434
Register(Register &&rhs)
Definition: register.h:82
BankInterface * parent() const override
Definition: register.h:445
Register & operator=(Register &&rhs)
Definition: register.h:91
friend std::ostream & operator<<(std::ostream &stream, const Register &reg)
Definition: register.h:106
void reset() override
Definition: register.h:152
uint64_t read(uint64_t enabled_bits) override
Definition: register.h:237
uint64_t get() const override
Definition: register.h:194
void parse_field(const field_t &f) override
Definition: register.h:407
unsigned number_of_bytes() const override
Definition: register.h:134
MappableConfObject * dev_obj() const override
Definition: register.h:126
#define SIM_LOG_INFO_STR(level, obj, group, str)
Special macro to handle string object (for example, fmt::format)
Definition: log.h:31
#define SIM_LOG_ERROR_STR(obj, group, str)
Definition: log.h:40
Definition: attr-value.h:23
std::vector< std::pair< uint8_t *, uint8_t > > bits_type
Definition: field-interface.h:30
std::pair< size_t, size_t > overlap_range(size_t r1_start, size_t r1_end, size_t r2_start, size_t r2_end)
std::enable_if< std::is_enum< T >::value, attr_value_t >::type std_to_attr(const T &src)
Function transforms C++ enum type T to Simics attr_value_t.
Definition: attribute-traits.h:111
int array_index(const std::string &name)
Return the array index if name is using an array format like array[N].
std::tuple< Name, Description, Offset, BitWidth > field_t
Definition: field-type.h:38
std::vector< uint8_t * > register_memory_t
Definition: register-type.h:52
detail::ConstSizeT BitWidth
Type used for the number/width of bit.
Definition: common-types.h:49
detail::ConstSizeT Offset
Type used for memory address offset.
Definition: common-types.h:46
Definition: common-types.h:63