C++ Device API Reference Manual
Reference documentation for the Simics C++ Device API.
 
Loading...
Searching...
No Matches
bank-port.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_BANK_PORT_H
17#define SIMICS_BANK_PORT_H
18
19#include <simics/base/attr-value.h>
20#include <simics/base/memory.h> // exception_type_t
21#include <simics/base/notifier.h> // SIM_register_notifier
22#include <simics/simulator-api.h> // SIM_hap_XXX
23#include <simics/c++/model-iface/bank-instrumentation.h>
24#include <simics/c++/model-iface/register-view.h>
25#include <simics/c++/model-iface/register-view-read-only.h>
26#include <simics/c++/model-iface/transaction.h>
27
28#include <initializer_list>
29#include <memory>
30#include <stdexcept> // invalid_argument
31#include <string>
32#include <string_view>
33#include <tuple> // tie
34#include <type_traits> // is_base_of
35#include <utility>
36#include <vector>
37
38#include "simics/attribute-traits.h" // checkSizeOverflowSimicsAttribute
39#include "simics/bank.h"
43#include "simics/conf-class.h"
44#include "simics/conf-object.h"
45#include "simics/detail/conf-object-util.h" // get_interface
47#include "simics/port.h"
49
50namespace simics {
51
52class RegisterInterface;
53
64template <typename TParent>
65class BankPort : public Port<TParent>,
66 public BankPortInterface,
68 public iface::RegisterViewInterface,
69 public iface::RegisterViewReadOnlyInterface,
70 public iface::RegisterViewCatalogInterface,
71 public iface::TransactionInterface {
72 static_assert(
73 std::is_base_of<MappableConfObject, TParent>::value,
74 "BankPort requires the parent class be a MappableConfObject");
75
76 public:
77 /*
78 * CTOR used for the "by code" modeling option
79 * "by code" option is used when the bank is created and initialized
80 * explicitly by code as a class member variable of a bank port.
81 */
82 explicit BankPort(ConfObjectRef o): Port<TParent>(o) {
83 set_bank_name_from_port_name(o.name());
84 SIM_hap_add_callback_obj(
85 "Core_Conf_Object_Created", o.object(), 0,
86 reinterpret_cast<obj_hap_func_t>(object_created), nullptr);
87 }
88
89 /*
90 * CTOR used for the "by data" modeling option
91 * "by data" option is used when the bank is created and initialized
92 * implicitly by the data provided in the constructor.
93 */
94 BankPort(ConfObjectRef o, const bank_t *bank): BankPort(o) {
95 if (bank == nullptr) {
96 throw std::invalid_argument("Bank pointer cannot be nullptr");
97 }
98 set_bank(*bank);
99 }
100
101 // non-copyable
102 BankPort(const BankPort &) = delete;
103 BankPort& operator=(const BankPort &) = delete;
104
105 virtual ~BankPort() {
106 SIM_hap_delete_callback_obj(
107 "Core_Conf_Object_Created", Port<TParent>::obj().object(),
108 reinterpret_cast<obj_hap_func_t>(object_created), nullptr);
109 }
110
112 static void addBankProperties(ConfClass *cls) {
113 cls->add(iface::TransactionInterface::Info());
114 cls->add(iface::RegisterViewInterface::Info());
115 cls->add(iface::RegisterViewReadOnlyInterface::Info());
116 cls->add(iface::RegisterViewCatalogInterface::Info());
117 cls->add(iface::BankInstrumentationSubscribeInterface::Info());
118 cls->add(iface::InstrumentationOrderInterface::Info());
119 cls->add(LogGroups{"Register_Read", "Register_Write",
120 "Register_Read_Exception",
121 "Register_Write_Exception"});
122 SIM_register_notifier(*cls, Sim_Notify_Bank_Register_Value_Change,
123 NULL /* default description works well */);
124 }
125
126 // BankPortInterface
127 std::string_view bank_name() const override {
128 return bank_name_;
129 }
130
131 const BankInterface *bank_iface() const override {
132 return bank_iface_;
133 }
134
135 MappableConfObject *dev_obj() const override {
136 return Port<TParent>::parent();
137 };
138
139 void set_bank(const bank_t &bank) override {
140 if (bank_iface_) {
141 SIM_LOG_ERROR(Port<TParent>::obj(), 0,
142 "bank iface can only be set once");
143 return;
144 }
145
146 bank_iface_ = dev_obj()->template get_iface<BankInterface>(bank_name_);
147 if (bank_iface_) {
148 SIM_LOG_INFO(3, Port<TParent>::obj(), 0,
149 "Used user defined bank for %s",
150 bank_name_.c_str());
151 } else {
152 allocated_bank_.reset(new Bank(dev_obj(), bank_name_));
153 bank_iface_ = allocated_bank_.get();
154 SIM_LOG_INFO(3, Port<TParent>::obj(), 0,
155 "Created a new default bank for %s",
156 bank_name_.c_str());
157 }
158 auto &[name, desc, registers] = bank;
159 bank_iface_->set_description(desc);
160 bank_iface_->set_callbacks(this);
161 for (const auto &reg : registers) {
162 bank_iface_->add_register(reg);
163 }
164 }
165
166 // iface::TransactionInterface
167 exception_type_t issue(transaction_t *t, uint64 addr) override {
168 if (!validate_bank_iface()) {
169 return Sim_PE_IO_Not_Taken;
170 }
171 return bank_iface_->transaction_access(t, addr);
172 }
173
174 // iface::RegisterViewInterface
175 const char *description() override {
176 if (!validate_bank_iface()) {
177 return nullptr;
178 }
179 return bank_iface_->description().data();
180 }
181 bool big_endian_bitorder() override {
182 return Port<TParent>::parent()->big_endian_bitorder();
183 }
184 unsigned number_of_registers() override {
185 return regs_offsets_.size();
186 }
187 attr_value_t register_info(unsigned reg) override {
188 auto [reg_offset, reg_iface] = register_at_index(reg);
189 if (reg_iface) {
190 return register_info(reg_offset,
191 bank_iface_->get_byte_order(),
192 reg_iface);
193 }
194 return SIM_make_attr_nil();
195 }
196 uint64 get_register_value(unsigned reg) override {
197 RegisterInterface *iface = nullptr;
198 std::tie(std::ignore, iface) = register_at_index(reg);
199 if (iface) {
200 return iface->get();
201 }
202 return 0;
203 }
204 void set_register_value(unsigned reg, uint64 val) override {
205 RegisterInterface *iface = nullptr;
206 std::tie(std::ignore, iface) = register_at_index(reg);
207 if (iface) {
208 iface->set(val);
209 }
210 }
211
212 // iface::RegisterViewReadOnlyInterface
213 bool is_read_only(unsigned reg) override {
214 RegisterInterface *iface = nullptr;
215 std::tie(std::ignore, iface) = register_at_index(reg);
216 return iface ? iface->is_read_only() : false;
217 }
218
219 // iface::RegisterViewCatalogInterface
220 attr_value_t register_names() override {
221 auto number_of_regs = number_of_registers();
222 attr_value_t ret = SIM_alloc_attr_list(number_of_regs);
223 RegisterInterface *iface = nullptr;
224 for (unsigned i = 0; i < number_of_regs; ++i) {
225 std::tie(std::ignore, iface) = register_at_index(i);
226 if (iface == nullptr) {
227 SIM_LOG_ERROR(Port<TParent>::obj(), 0,
228 "Invalid register index %d", i);
229 SIM_attr_list_set_item(&ret, i, SIM_make_attr_nil());
230 continue;
231 }
232 SIM_attr_list_set_item(&ret, i,
233 SIM_make_attr_string(iface->name().data()));
234 }
235 return ret;
236 }
237
238 attr_value_t register_offsets() override {
239 return std_to_attr(regs_offsets_);
240 }
241
242 private:
243 bool validate_bank_iface() const override {
244#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
245 if (bank_iface_ == nullptr) { [[unlikely]] // NOLINT(whitespace/newline,whitespace/line_length)
246#else
247 if (bank_iface_ == nullptr) {
248#endif
249 SIM_LOG_ERROR(Port<TParent>::obj(), 0,
250 "BankPort should have one bank");
251 return false;
252 }
253 return true;
254 }
255
256 // Initialize the register offsets for better performance
257 // when using the register_view interface
258 void init_register_offsets() {
259 const auto &mapped_regs = bank_iface_->mapped_registers();
260 regs_offsets_.clear();
261 regs_offsets_.reserve(mapped_regs.size());
262 for (const auto& pair : mapped_regs) {
263 regs_offsets_.push_back(pair.first);
264 }
265 }
266
268 static void object_created(lang_void *, conf_object_t *obj) {
269 auto *iface = detail::get_interface<BankPort<TParent>>(obj);
270 if (iface->validate_bank_iface()) {
271 // Register can't be added after the bank port is finalized,
272 // so it is safe to initialize the register offsets now
273 iface->init_register_offsets();
274 }
275 }
276
277 static attr_value_t register_info(size_t address, ByteOrder bo,
278 const RegisterInterface *i) {
279 attr_value_t info = SIM_alloc_attr_list(6);
280 SIM_attr_list_set_item(&info, 0,
281 SIM_make_attr_string(i->name().data()));
282 SIM_attr_list_set_item(&info, 1,
283 SIM_make_attr_string(i->description().c_str()));
284 SIM_attr_list_set_item(&info, 2,
285 SIM_make_attr_uint64(i->number_of_bytes()));
286 SIM_attr_list_set_item(&info, 3, SIM_make_attr_uint64(address));
287
288 auto fields_info = i->fields_info();
289 auto number_of_fields = fields_info.size();
290 // The forth attr in info is a list fields
291 checkSizeOverflowSimicsAttribute(number_of_fields);
292 attr_value_t fields = SIM_alloc_attr_list(
293 static_cast<unsigned>(number_of_fields));
294 unsigned index = 0;
295 for (const auto &[name, desc, offset, width] : fields_info) {
296 // Each attr in fields is another list field_info
297 attr_value_t field_info = SIM_alloc_attr_list(4);
298 SIM_attr_list_set_item(&field_info, 0,
299 SIM_make_attr_string(name.data()));
300 SIM_attr_list_set_item(&field_info, 1,
301 SIM_make_attr_string(desc.data()));
302 SIM_attr_list_set_item(&field_info, 2,
303 SIM_make_attr_uint64(offset));
304 SIM_attr_list_set_item(&field_info, 3,
305 SIM_make_attr_uint64(offset + width - 1));
306 SIM_attr_list_set_item(&fields, index++, field_info);
307 }
308 SIM_attr_list_set_item(&info, 4, fields);
309 SIM_attr_list_set_item(&info, 5,
310 SIM_make_attr_boolean(bo == ByteOrder::BE));
311 return info;
312 }
313
316 void set_bank_name_from_port_name(const std::string &port_name) {
317 auto pos = port_name.rfind(".bank.");
318 if (pos == std::string::npos) {
319 throw std::invalid_argument(
320 "Invalid bank port name (" + port_name + ")");
321 }
322 bank_name_ = port_name.substr(pos + 6);
323 }
324
325 std::pair<size_t, RegisterInterface *> register_at_index(unsigned index) {
326 size_t reg_offset {0};
327 RegisterInterface *reg_iface {nullptr};
328 try {
329 reg_offset = regs_offsets_.at(index);
330 } catch (const std::out_of_range &) {
331 SIM_LOG_ERROR(Port<TParent>::obj(), 0,
332 "Invalid register index %d", index);
333 return {reg_offset, reg_iface};
334 }
335 if (validate_bank_iface()) {
336 reg_iface = bank_iface_->mapped_registers().at(reg_offset);
337 }
338 return {reg_offset, reg_iface};
339 }
340
341 // Points to the actual bank interface
342 BankInterface *bank_iface_ { nullptr };
343 // Name of the bank
344 std::string bank_name_;
345 // @internal: record the heap allocated Bank
346 std::unique_ptr<BankInterface> allocated_bank_;
347 // @internal: list of all register offsets by ascending order
348 std::vector<size_t> regs_offsets_;
349};
350
351// This class defines a SimpleBankPort, which is a specialized bank port object.
352// It contains a public member 'b' of type TBank, representing a bank.
353template<typename TPortBank, typename... Args>
354class SimpleBankPort : public BankPort<MappableConfObject> {
355 public:
356 explicit SimpleBankPort(ConfObjectRef o, Args... args)
358 b(this, "A bank created through the SimicsBankPort utility class",
359 args...) {}
360
361 TPortBank b;
362};
363
393template <typename TBankPort> ConfClassPtr
394make_bank_port(const std::string &name, const std::string &desc) {
395 static_assert(std::is_base_of<BankPort<typename TBankPort::ParentType>,
396 TBankPort>::value,
397 "TBankPort must be derived from BankPort");
398 auto port = make_class<TBankPort>(name, "", desc);
399 TBankPort::addBankProperties(port.get());
400 return port;
401}
402template <typename TBankPort, typename TArg> ConfClassPtr
403make_bank_port(const std::string &name, const std::string &desc, TArg *arg) {
404 static_assert(std::is_base_of<BankPort<typename TBankPort::ParentType>,
405 TBankPort>::value,
406 "TBankPort must be derived from BankPort");
407 auto port = make_class<TBankPort>(name, "", desc, arg);
408 TBankPort::addBankProperties(port.get());
409 return port;
410}
411
430template <typename TParent>
432 const auto &[name, desc, registers] = bank;
434 cls->name() + SEPARATOR + std::string(name.base_name()),
435 desc.data(), &bank),
436 std::string("bank.") + name.data());
437}
438// When passing initializer_list by value, only the wrapper (which contains
439// pointers to the elements) is copied, not the elements themselves.
440template <typename TParent>
442 ConfClass *cls, std::initializer_list<bank_t> register_data) {
443 for (const auto &bank : register_data) {
444 create_hierarchy_from_register_data<TParent>(cls, bank);
445 }
446}
447
448} // namespace simics
449
450#endif
#define NULL
Definition: _null.h:24
Definition: bank-instrumentation-subscribe-connection.h:46
An interface implemented by a Simics bank.
Definition: bank-interface.h:47
virtual void set_description(std::string_view desc)=0
Set the description for the bank.
virtual void add_register(const register_t &reg)=0
Parse a register name and add register to the bank.
virtual void set_callbacks(BankIssueCallbacksInterface *callbacks)=0
Set the callbacks for bank issues.
virtual const std::map< size_t, RegisterInterface * > & mapped_registers() const =0
Get all mapped registers on the bank ordered by offset.
virtual exception_type_t transaction_access(transaction_t *t, uint64_t offset)=0
Entry point for a memory access from the transaction interface.
virtual const std::string & description() const =0
Get the description of the bank.
virtual ByteOrder get_byte_order() const =0
Get the byte order of the bank.
Definition: bank-port-interface.h:31
Extends Port with bank required interfaces.
Definition: bank-port.h:71
BankPort & operator=(const BankPort &)=delete
const char * description() override
Definition: bank-port.h:175
std::string_view bank_name() const override
Definition: bank-port.h:127
BankPort(ConfObjectRef o, const bank_t *bank)
Definition: bank-port.h:94
void set_bank(const bank_t &bank) override
Definition: bank-port.h:139
attr_value_t register_names() override
Definition: bank-port.h:220
static void addBankProperties(ConfClass *cls)
Adds bank properties to the given class.
Definition: bank-port.h:112
uint64 get_register_value(unsigned reg) override
Definition: bank-port.h:196
bool is_read_only(unsigned reg) override
Definition: bank-port.h:213
virtual ~BankPort()
Definition: bank-port.h:105
attr_value_t register_offsets() override
Definition: bank-port.h:238
bool big_endian_bitorder() override
Definition: bank-port.h:181
unsigned number_of_registers() override
Definition: bank-port.h:184
BankPort(const BankPort &)=delete
exception_type_t issue(transaction_t *t, uint64 addr) override
Definition: bank-port.h:167
const BankInterface * bank_iface() const override
Definition: bank-port.h:131
attr_value_t register_info(unsigned reg) override
Definition: bank-port.h:187
MappableConfObject * dev_obj() const override
Definition: bank-port.h:135
void set_register_value(unsigned reg, uint64 val) override
Definition: bank-port.h:204
BankPort(ConfObjectRef o)
Definition: bank-port.h:82
Base class to represent a Simics register bank.
Definition: bank.h:51
Represents Simics C type conf_class_t.
Definition: conf-class.h:52
const std::string & name() const
Return the class name.
ConfClass * add(const iface::InterfaceInfo &iface)
Stores the provided InterfaceInfo for later registration.
Represents Simics C type conf_object_t.
Definition: conf-object.h:38
conf_object_t * object() const
Get a pointer to the configuration object represented by this ConfObjectRef.
Definition: conf-object.h:54
std::string name() const
Get the name of the underlying configuration object.
ConfObjectRef obj() const
Return a ConfObjectRef represents this object.
Definition: conf-object.h:137
Definition: mappable-conf-object.h:134
Extends ConfObject to add utilities to a Simics port object.
Definition: port.h:45
int index() const
Definition: port.h:76
const std::string & name() const
Definition: port.h:70
ParentType * parent() const
Definition: port.h:65
Definition: register-interface.h:37
virtual std::string_view name() const =0
Get the name of the register without level delimiters.
virtual bool is_read_only() const =0
Definition: bank-port.h:354
TPortBank b
Definition: bank-port.h:361
SimpleBankPort(ConfObjectRef o, Args... args)
Definition: bank-port.h:356
virtual uint64_t get() const =0
virtual void set(uint64_t value)=0
Definition: after-bank.h:33
std::initializer_list< std::string > LogGroups
Type used for log group names.
Definition: log.h:27
std::unique_ptr< ConfClass > ConfClassPtr
Definition: conf-class.h:38
std::tuple< Name, Description, std::vector< register_t > > bank_t
Definition: bank-type.h:38
ByteOrder
Definition: bank-interface.h:33
void create_hierarchy_from_register_data(ConfClass *cls, const bank_t &bank)
Registers bank data as port objects within a configuration class hierarchy.
Definition: bank-port.h:431
ConfClassPtr make_bank_port(const std::string &name, const std::string &desc)
Creates a bank port configuration class with specified attributes.
Definition: bank-port.h:394
void checkSizeOverflowSimicsAttribute(size_t size)
The maximum supported size for a Simics attribute dictionary/list/data is 2**32-1 bytes.
Definition: attribute-traits.h:40
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:163