C++ Device API Reference Manual
Reference documentation for the Simics C++ Device API.
 
Loading...
Searching...
No Matches
hierarchical-object.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_HIERARCHICAL_OBJECT_H
17#define SIMICS_HIERARCHICAL_OBJECT_H
18
19#include <simics/base/log.h> // SIM_LOG_XXX
20#include <fmt/fmt/format.h>
21#include <string_view>
22#include <string>
23#include <stdexcept>
24#include <algorithm> // count
25#include <utility> // swap
26
27#include "conf-object.h" // ConfObjectRef
29#include "log.h"
31
32namespace simics {
33
34// TODO(xiuliang): Where to find the register name at compile time?
35// #define SIMICS_REGISTER(R)
36// RegisterInterface* get##R##() { return lookup_register(#R); }
37
38// The hierarchy separator between bank, register and field names
39constexpr static const char &SEPARATOR = '.';
40
41// Base class for Bank/Register/Field class
42// coverity[rule_of_five_violation:FALSE]
44 public:
45 // @param name unique hierarchical name of a bank/register/field
47 const std::string &name)
48 : dev_obj_(dev_obj),
49 hierarchical_name_(name) {
50 if (dev_obj == nullptr) {
51 throw std::invalid_argument {
52 "HierarchicalObject cannot be constructed from a NULL dev_obj"
53 };
54 }
55 init();
56 }
58 const std::string &name,
59 FieldInterface *iface)
61 init_iface(iface);
62 }
64 const std::string &name,
65 RegisterInterface *iface)
67 init_iface(iface);
68 }
70 const std::string &name,
71 BankInterface *iface)
73 init_iface(iface);
74 }
75
77 auto *obj = bank_obj_ref_.object();
78 if (obj) {
79 if (SIM_object_is_configured(obj)) {
80 if (!SIM_marked_for_deletion(obj)) {
81 SIM_LOG_CRITICAL(obj, 0,
82 "Hierarchical object can't be deleted"
83 " during the simulation");
84 }
85 }
86 }
87 }
88
89 // No duplication
92
94 : dev_obj_(rhs.dev_obj_),
95 hierarchical_name_(std::move(rhs.hierarchical_name_)),
96 desc_(std::move(rhs.desc_)),
97 bank_obj_ref_(rhs.bank_obj_ref_),
98 level_(rhs.level_) {}
100 // check for self-assignment
101 if (this == &rhs)
102 return *this;
103
104 HierarchicalObject temp(std::move(rhs));
105 std::swap(dev_obj_, temp.dev_obj_);
106 std::swap(hierarchical_name_, temp.hierarchical_name_);
107 std::swap(desc_, temp.desc_);
108 std::swap(bank_obj_ref_, temp.bank_obj_ref_);
109 std::swap(level_, temp.level_);
110 return *this;
111 }
112
114 if (level_ != Level::BANK) {
115 std::string err = "Bank name (" + hierarchical_name_ \
116 + ") does not match the bank level (bankA)";
118 throw std::invalid_argument { err };
119 }
120 dev_obj_->set_iface<BankInterface>(hierarchical_name_, iface);
121 }
122
124 if (level_ != Level::REGISTER) {
125 std::string err = "Register name (" + hierarchical_name_ \
126 + ") does not match the register level (bankA.registerB)";
128 throw std::invalid_argument { err };
129 }
130 dev_obj_->set_iface<RegisterInterface>(hierarchical_name_, iface);
131 }
132
134 if (level_ != Level::FIELD) {
135 std::string err = "Field name (" + hierarchical_name_ \
136 + ") does not match the field level (bankA.registerB.fieldC)";
138 throw std::invalid_argument { err };
139 }
140 dev_obj_->set_iface<FieldInterface>(hierarchical_name_, iface);
141 }
142
143 const std::string &hierarchical_name() const override {
144 return hierarchical_name_;
145 }
146
147 std::string_view name() const override {
148 if (hierarchy_level() == Level::BANK) {
149 return hierarchical_name();
150 } else {
151 return {hierarchical_name().data() \
152 + hierarchical_name().rfind(SEPARATOR) + 1};
153 }
154 }
155
156 const std::string &description() const override {
157 return desc_;
158 }
159
160 void set_description(std::string_view desc) override {
161 desc_ = desc;
162 }
163
164 Level hierarchy_level() const override {
165 return level_;
166 }
167
168 std::string_view bank_name() const override {
169 if (hierarchy_level() == Level::BANK) {
170 return name();
171 } else {
172 return {hierarchical_name().data(),
173 hierarchical_name().find(SEPARATOR)};
174 }
175 }
176
177 MappableConfObject *dev_obj() const override {
178 return dev_obj_;
179 }
180
181 ConfObjectRef bank_obj_ref() const override {
182 return bank_obj_ref_;
183 }
184
185 template<typename T> T *dev_ptr() {
186 static_assert(std::is_base_of<MappableConfObject, T>::value,
187 "T needs be a MappableConfObject");
188 return dynamic_cast<T *>(dev_obj());
189 }
190
191 std::string_view parent_name() const override {
192 if (hierarchy_level() == Level::BANK) {
193 return {};
194 } else {
195 return {hierarchical_name().data(),
196 hierarchical_name().rfind(SEPARATOR)};
197 }
198 }
199
200 FieldInterface *lookup_field(const std::string &name) const override {
201 FieldInterface *field_interface = nullptr;
202 if (!dev_obj_->finalized()) {
203 SIM_LOG_ERROR(dev_obj_->obj(), 0,
204 "Look up field should be called after finalize"
205 " phase");
206 return field_interface;
207 }
209 SIM_LOG_ERROR_STR(dev_obj_->obj(), 0,
210 fmt::format("Invalid field name: {}", name));
211 return field_interface;
212 }
213
214 int field_name_level = level_of_hierarchical_name(name);
215 if (field_name_level == 0) {
216 // With field name only like "f2"
217 if (level_ == Level::REGISTER) {
218 field_interface = dev_obj_->get_iface<FieldInterface>(
219 hierarchical_name_ + SEPARATOR + name);
220 } else if (level_ == Level::FIELD) {
221 field_interface = dev_obj_->get_iface<FieldInterface>(
222 hierarchical_name_.substr(0, hierarchical_name_.rfind(
223 SEPARATOR)) \
224 + SEPARATOR + name);
225 } else {
226 SIM_LOG_ERROR(dev_obj_->obj(), 0,
227 "Unable to lookup a field with field name only"
228 " in a bank");
229 }
230 } else if (field_name_level == 1) {
231 // With field name only like "r1.f2"
232 field_interface = dev_obj_->get_iface<FieldInterface>(
233 std::string(bank_name()).append(1, SEPARATOR).append(name));
234 } else {
235 field_interface = dev_obj_->get_iface<FieldInterface>(name);
236 }
237
238 if (!field_interface) {
239 SIM_LOG_ERROR_STR(dev_obj_->obj(), 0,
240 fmt::format("Lookup field failed: {}", name));
241 }
242 return field_interface;
243 }
244
245 RegisterInterface *lookup_register(const std::string &name) const override {
246 RegisterInterface *register_interface = nullptr;
247 if (!dev_obj_->finalized()) {
248 SIM_LOG_ERROR(dev_obj_->obj(), 0,
249 "Look up register should be called after finalize"
250 " phase");
251 return register_interface;
252 }
254 SIM_LOG_ERROR_STR(dev_obj_->obj(), 0,
255 fmt::format("Invalid register name: {}", name));
256 return register_interface;
257 }
258
259 int register_name_level = level_of_hierarchical_name(name);
260 if (register_name_level > static_cast<int>(Level::REGISTER)) {
261 SIM_LOG_ERROR_STR(dev_obj_->obj(), 0,
262 fmt::format("Invalid register name: {}", name));
263 } else {
264 register_interface = dev_obj_->get_iface<RegisterInterface>(
265 std::string(bank_name()).append(1, SEPARATOR).append(name));
266 }
267
268 if (!register_interface) {
269 SIM_LOG_ERROR_STR(dev_obj_->obj(), 0,
270 fmt::format("Lookup register failed: {}", name));
271 }
272 return register_interface;
273 }
274
275 BankInterface *lookup_bank(const std::string &name) const override {
276 BankInterface *bank_interface = nullptr;
277 if (!dev_obj_->finalized()) {
278 SIM_LOG_ERROR(dev_obj_->obj(), 0,
279 "Look up bank should be called after finalize phase");
280 return bank_interface;
281 }
283 SIM_LOG_ERROR_STR(dev_obj_->obj(), 0,
284 fmt::format("Invalid bank name: {}", name));
285 return bank_interface;
286 }
287
288 int bank_name_level = level_of_hierarchical_name(name);
289 if (bank_name_level > static_cast<int>(Level::BANK)) {
290 SIM_LOG_ERROR_STR(dev_obj_->obj(), 0,
291 fmt::format("Invalid bank name: {}", name));
292 } else {
293 bank_interface = dev_obj_->get_iface<BankInterface>(name);
294 }
295
296 if (!bank_interface) {
297 SIM_LOG_ERROR_STR(dev_obj_->obj(), 0,
298 fmt::format("Lookup bank failed: {}", name));
299 }
300 return bank_interface;
301 }
302
303 static bool is_valid_hierarchical_name(std::string_view name) {
304 // The allowed characters in the hierarchical object's name
305 static const char *allowed_characters {
306 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ[]._"
307 };
308
309 if (name.empty()) {
310 return false;
311 }
312 if (isdigit(name[0]) || name[0] == '['
313 || name[0] == ']' || name[0] == '_') {
314 return false;
315 }
316 if (name.find_first_not_of(allowed_characters) != std::string::npos) {
317 return false;
318 }
319 if (std::count(name.cbegin(), name.cend(), SEPARATOR) > 2) {
320 return false;
321 }
322 if (name.find(std::string(2, SEPARATOR)) != std::string::npos) {
323 return false;
324 }
325 if (name.find(SEPARATOR) == 0
326 || name.rfind(SEPARATOR) == name.length() - 1) {
327 return false;
328 }
329 return true;
330 }
331
332 static int level_of_hierarchical_name(std::string_view name) {
333 assert(!name.empty());
335
336 return std::count(name.cbegin(), name.cend(), SEPARATOR);
337 }
338
340 static const uint64_t Register_Read {1};
341 static const uint64_t Register_Write {2};
342
343 private:
344 void init() {
345 if (!is_valid_hierarchical_name(hierarchical_name_)) {
346 std::string err = "Cannot set with invalid name string: " \
347 + hierarchical_name_;
348 SIM_LOG_ERROR_STR(dev_obj_->obj(), 0, err);
349 throw std::invalid_argument { err };
350 }
351
352 level_ = static_cast<Level>(
353 level_of_hierarchical_name(hierarchical_name_));
354
355 std::string bank_name {hierarchical_name_};
356 if (level_ != Level::BANK) {
357 auto pos_first_separator = hierarchical_name_.find(SEPARATOR);
358 assert(pos_first_separator != std::string::npos);
359 bank_name = hierarchical_name_.substr(0, pos_first_separator);
360 }
361
362 bank_obj_ref_ = SIM_object_descendant(
363 dev_obj_->obj(), ("bank." + bank_name).c_str());
364 if (bank_obj_ref_.object() == nullptr) {
365 std::string err = fmt::format("{}.bank.{} does not exist",
366 dev_obj_->obj().name(),
367 bank_name);
368 SIM_LOG_ERROR_STR(dev_obj_->obj(), 0, err);
369 throw std::invalid_argument { err };
370 }
371 }
372
373 MappableConfObject *dev_obj_;
374 std::string hierarchical_name_;
375 std::string desc_;
376 ConfObjectRef bank_obj_ref_;
377 Level level_;
378};
379
380} // namespace simics
381
382#endif
Definition: bank-interface.h:45
Represents Simics C type conf_object_t.
Definition: conf-object.h:37
conf_object_t * object() const
Get a pointer to the configuration object represented by this ConfObjectRef.
Definition: conf-object.h:57
const std::string & name() const
Get the name of the underlying configuration object.
virtual bool finalized()
Return if the finalize method has been called.
Definition: conf-object.h:137
ConfObjectRef obj() const
Return a ConfObjectRef represents this object.
Definition: conf-object.h:134
Definition: field-interface.h:34
Definition: hierarchical-object-interface.h:32
Definition: hierarchical-object.h:43
T * dev_ptr()
Definition: hierarchical-object.h:185
static const uint64_t Register_Read
Log group ID for Register_Read and Register_Write is fixed.
Definition: hierarchical-object.h:340
HierarchicalObject(HierarchicalObject &&rhs) noexcept
Definition: hierarchical-object.h:93
void init_iface(BankInterface *iface)
Definition: hierarchical-object.h:113
HierarchicalObject & operator=(const HierarchicalObject &)=delete
virtual ~HierarchicalObject()
Definition: hierarchical-object.h:76
HierarchicalObject(MappableConfObject *dev_obj, const std::string &name, RegisterInterface *iface)
Definition: hierarchical-object.h:63
HierarchicalObject(MappableConfObject *dev_obj, const std::string &name, BankInterface *iface)
Definition: hierarchical-object.h:69
std::string_view bank_name() const override
Definition: hierarchical-object.h:168
BankInterface * lookup_bank(const std::string &name) const override
Definition: hierarchical-object.h:275
static const uint64_t Register_Write
Definition: hierarchical-object.h:341
HierarchicalObject(MappableConfObject *dev_obj, const std::string &name, FieldInterface *iface)
Definition: hierarchical-object.h:57
void init_iface(FieldInterface *iface)
Definition: hierarchical-object.h:133
RegisterInterface * lookup_register(const std::string &name) const override
Definition: hierarchical-object.h:245
ConfObjectRef bank_obj_ref() const override
Definition: hierarchical-object.h:181
HierarchicalObject(MappableConfObject *dev_obj, const std::string &name)
Definition: hierarchical-object.h:46
FieldInterface * lookup_field(const std::string &name) const override
Definition: hierarchical-object.h:200
HierarchicalObject & operator=(HierarchicalObject &&rhs) noexcept
Definition: hierarchical-object.h:99
void init_iface(RegisterInterface *iface)
Definition: hierarchical-object.h:123
static bool is_valid_hierarchical_name(std::string_view name)
Definition: hierarchical-object.h:303
std::string_view name() const override
Definition: hierarchical-object.h:147
Level hierarchy_level() const override
Definition: hierarchical-object.h:164
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
static int level_of_hierarchical_name(std::string_view name)
Definition: hierarchical-object.h:332
HierarchicalObject(const HierarchicalObject &)=delete
const std::string & hierarchical_name() const override
Definition: hierarchical-object.h:143
Definition: mappable-conf-object.h:131
void set_iface(const std::string &name, IFACE *iface)
Definition: mappable-conf-object.h:138
IFACE * get_iface(const std::string &name) const
Definition: mappable-conf-object.h:170
Definition: register-interface.h:36
#define SIM_LOG_CRITICAL_STR(obj, group, str)
Definition: log.h:43
#define SIM_LOG_ERROR_STR(obj, group, str)
Definition: log.h:40
Definition: attr-value.h:23
Level
Definition: hierarchical-object-interface.h:30