16#ifndef SIMICS_REGISTER_H
17#define SIMICS_REGISTER_H
19#include <simics/base/conf-object.h>
20#include <simics/base/notifier.h>
21#include <simics/simulator/conf-object.h>
44static unsigned find_first(
const std::bitset<64> &bits) {
46 while (idx < 64 && !bits[idx]) {
52extern std::pair<size_t, size_t>
overlap_range(
size_t r1_start,
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_)) {
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_);
108 stream <<
"0x" << std::setfill(
'0')
110 << std::hex << reg.
get();
114 std::string_view
name()
const override {
135 return byte_pointers_.size();
139 uint64_t init_val)
override {
144 if (parent_ ==
nullptr) {
149 add_register_as_simics_attribute(
this);
165 if (!byte_pointers_.empty()) {
166 SIM_LOG_SPEC_VIOLATION(
168 "Cannot reset the register byte pointers, ignored");
171 if (byte_pointers.size() > 8 || byte_pointers.empty()) {
174 "The supported register size is [1-8] bytes");
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()) {
183 "The byte_pointers contains duplicate items");
188 byte_pointers_ = byte_pointers;
190 byte_mask_ = std::numeric_limits<uint64_t>::max();
194 uint64_t
get()
const override {
195 uint64_t value = read_from_byte_pointers();
196 if (fields_.empty()) {
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;
207 value &= ~(bits_mask << offset);
208 value |= (f->get() & bits_mask) << offset;
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)) {
219 *byte_pointer = v & 0xff;
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;
230 f->set((value >> offset) & bits_mask);
233 SIM_notify(
bank_obj_ref(), Sim_Notify_Bank_Register_Value_Change);
237 uint64_t
read(uint64_t enabled_bits)
override {
238 enabled_bits &= byte_mask_;
239 if (enabled_bits == 0) {
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",
255 bool partial = enabled_bits != byte_mask_;
257 if (fields_.empty()) {
258 ret =
get() & enabled_bits;
260 bits &= read_from_byte_pointers();
264 auto first_field = fields_.upper_bound(start_bit_offset);
265 if (first_field != fields_.begin()) {
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;
275 start_bit_offset, end_bit_offset,
276 field_offset, field_end_range);
277 size_t bits_to_read = overlap_end - overlap_start;
280 if (bits_to_read == 0) {
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;
290 uint64_t field_val = field_iface->read(bits_mask) & bits_mask;
291 field_val >>= bits_shift;
293 for (
unsigned index = 0; index < bits_to_read; ++index) {
294 bits[index + overlap_start] = (field_val >> index) & 1;
298 ret = bits.to_ullong();
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));
310 fmt::format(
"Partial read from register {}:"
311 " bits {}-{} -> {:#x}",
name(),
313 end_bit_offset - 1, ret));
317 fmt::format(
"Read from register {} -> {:#x}",
324 void write(uint64_t value, uint64_t enabled_bits)
override {
325 enabled_bits &= byte_mask_;
326 if (enabled_bits == 0) {
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",
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));
351 fmt::format(
"Partial write to register {}:"
352 " bits {}-{} <- {:#x}",
name(),
355 value & enabled_bits));
359 fmt::format(
"Write to register {} <- {:#x}",
360 name(), value & enabled_bits));
363 if (fields_.empty()) {
364 set((
get() & ~enabled_bits) | (value & enabled_bits));
370 auto first_field = fields_.upper_bound(start_bit_offset);
371 if (first_field != fields_.begin()) {
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;
381 start_bit_offset, end_bit_offset,
382 field_offset, field_end_range);
383 size_t bits_to_write = overlap_end - overlap_start;
386 if (bits_to_write == 0) {
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;
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;
399 field_iface->write(write_value, bits_mask);
410 fmt::format(
"Cannot add fields for register ({})"
411 " when device has finalized",
416 const auto &[
name, desc, offset, width] = f;
420 "Ignored invalid field as the width is 0");
424 if (
name.array_str().empty()) {
425 add_field(
name, desc, offset, width);
427 for (
const auto &[_name, _offset]
428 :
name.arrayNamesToOffsets(width)) {
429 add_field(_name, desc, offset + _offset, width);
435 std::vector<field_t> info;
436 for (
auto const &field : fields_) {
437 info.emplace_back(field.second->name().data(),
438 field.second->description(),
440 field.second->number_of_bits());
452 init_val_ = init_val;
456 static void add_register_as_simics_attribute(
458 auto *bank_class = SIM_object_class(iface->
bank_obj_ref());
460 auto reg_name = iface->
name();
466 std::string reg_name_wo_brackets {
467 reg_name.substr(0, reg_name.find(
'['))
470 if (SIM_class_has_attribute(bank_class,
471 reg_name_wo_brackets.c_str())) {
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 +
"+]";
480 auto hashed = MapNameToInterfaceObject<
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(),
490 static attr_value_t get_reg_array(
int indices,
int dim_index,
491 MappableConfObject *obj,
492 const std::string &base_name) {
494 if (dim_index == indices) {
496 std::vector<size_t> values;
498 auto *reg_iface = obj->template get_iface<
502 if (reg_iface ==
nullptr) {
505 values.push_back(reg_iface->get());
508 if (values.empty()) {
509 return SIM_make_attr_nil();
514 std::vector<attr_value_t> values;
516 auto attr = get_reg_array(indices, dim_index + 1, obj,
517 fmt::format(
"{}[{}]", base_name,
519 if (SIM_attr_is_nil(attr)) {
522 values.push_back(attr);
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();
539 auto reg_name = reg_iface->name();
540 auto indices = std::count(reg_name.cbegin(),
541 reg_name.cend(),
'[');
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);
552 static set_error_t set_reg_array(
int indices,
int dim_index,
553 MappableConfObject *obj,
554 const std::string &base_name,
557 if (dim_index == indices) {
559 auto values = attr_to_std<std::vector<size_t>>(*val);
561 auto *reg_iface = obj->template get_iface<
565 if (reg_iface ==
nullptr) {
568 return Sim_Set_Illegal_Index;
576 return Sim_Set_Illegal_Index;
579 auto values = attr_to_std<std::vector<attr_value_t>>(*val);
581 auto status = set_reg_array(indices, dim_index + 1, obj,
582 fmt::format(
"{}[{}]", base_name,
585 if (status == Sim_Set_Illegal_Index) {
589 return Sim_Set_Illegal_Index;
598 static set_error_t set_reg(
conf_object_t *obj, attr_value_t *val,
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);
605 return Sim_Set_Interface_Not_Found;
608 auto reg_name = reg_iface->name();
609 auto indices = std::count(reg_name.cbegin(),
610 reg_name.cend(),
'[');
612 reg_iface->set(attr_to_std<size_t>(*val));
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);
626 "The supported register size is [1-8] bytes");
631 fmt::format(
"The memory size({}) does not fit "
632 "the number of bytes({})",
633 byte_pointers_.size(),
640 bool has_range_overlap(
size_t lsb,
size_t msb)
const {
641 return std::any_of(fields_.cbegin(), fields_.cend(),
643 return lsb < (p.first + p.second->number_of_bits())
649 void add_field(std::string_view field_name, std::string_view desc,
654 "Ignored invalid field as the offset exceeds"
655 " the number of bits");
659 if (has_range_overlap(offset, offset + width - 1)) {
661 "Ignored invalid field as it overlaps with"
666 const std::string 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 {}",
677 }
else if (fields_[offset]->number_of_bits() == 0) {
679 fmt::format(
"Used user defined field for {}",
682 fields_.erase(offset);
684 fmt::format(
"Duplicated field name({}) on same"
685 " register", field_name));
689 if (byte_pointers_.empty()) {
691 fmt::format(
"No storage allocated on register %s",
699 for (
unsigned i = offset / 8; i <= (offset + width - 1) / 8; ++i) {
700 uint8_t bits_mask = 0xff;
701 if (i == offset / 8) {
703 bits_mask <<= (offset % 8);
705 if (i == (offset + width - 1) / 8) {
707 uint8_t num_masked_bits = (offset + width) % 8;
708 if (num_masked_bits != 0) {
709 bits_mask &= (1 << num_masked_bits) - 1;
712 bits.push_back(std::make_pair(byte_pointers_[i], bits_mask));
714 fields_[offset]->init(desc, bits, offset);
717 uint64_t read_from_byte_pointers()
const {
720 for (
unsigned i = 0; i < num_bytes; ++i) {
721 result |= (uint64_t)(*byte_pointers_[i]) << (8 * i);
727 uint64_t init_val_ {0};
729 uint64_t byte_mask_ {std::numeric_limits<uint64_t>::max()};
735 std::map<size_t, FieldInterface *> fields_;
737 BankInterface *parent_ {
nullptr};
739 std::vector<std::unique_ptr<FieldInterface>> allocated_fields_;
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 ®)
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