C++ Device API Reference Manual
Reference documentation for the Simics C++ Device API.
 
Loading...
Searching...
No Matches
after.h
Go to the documentation of this file.
1// -*- mode: C++; c-file-style: "virtutech-c++" -*-
2
3/*
4 © 2024 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_AFTER_H
17#define SIMICS_AFTER_H
18
19#include <iostream>
20#include <string>
21#include <tuple>
22#include <typeinfo>
23#include <unordered_set>
24#include <utility>
25
27#include "simics/attr-value.h"
29#include "simics/event.h"
30
31namespace simics {
32
33/*
34 * This class serves as a manager for a collection of interfaces that implement
35 * the `AfterCallInterface`. It provides static methods to add, remove,
36 * and find interface instances based on their names.
37 */
38class AfterCall {
39 public:
40 static void addIface(AfterCallInterface *iface);
41 static void removeIface(AfterCallInterface *iface);
42 static AfterCallInterface *findIface(const std::string &name);
43
44 private:
45 static std::unordered_set<AfterCallInterface*> &getIfaces();
46};
47
48// FunctionCall contains information about a callable function, including
49// its name, arguments, and a pointer to the function itself.
50template<typename... Args>
52 public:
53 using FunctionType = void(*)(Args...);
54
55 FunctionCall(FunctionType func, const std::string &name)
56 : func_(func),
57 name_(name + typeid(func).name()) {}
58
59 std::string name() const override {
60 return name_;
61 }
62
63 void set_args(const attr_value_t &value) override {
64 args_ = attr_to_std<std::tuple<Args...>>(value);
65 }
66
68 // The allocated pointer is deleted after the function call is invoked
69 return new FunctionCall<Args...>(*this);
70 }
71
72 attr_value_t get_value() override {
73 return std_to_attr(std::make_pair(name_, args_));
74 }
75
76 private:
77 // Invokes the stored function with the current arguments
78 void invoke() override {
79 invoke_impl(std::index_sequence_for<Args...>{});
80 }
81
82 // Helper function to unpack the tuple and call the function
83 template<std::size_t... I>
84 void invoke_impl(std::index_sequence<I...>) {
85 func_(std::get<I>(args_)...);
86 }
87
88 FunctionType func_;
89 std::string name_;
90 std::tuple<Args...> args_;
91};
92
93// MemberFunctionCall contains information about a class member function,
94// including a pointer to the object, the function's name, its arguments,
95// and a pointer to the member function itself
96template<typename Class, typename... Args>
98 public:
99 using MemberFunctionType = void (Class::*)(Args...);
100
102 : func_(func), name_(name + typeid(func).name()),
103 obj_(nullptr) {}
104
105 std::string name() const override {
106 return name_;
107 }
108
109 // Sets the arguments for the member function call from a given
110 // attribute value.
111 // The first element is treated as a reference to the object, and
112 // subsequent elements are treated as arguments for the member function
113 void set_args(const attr_value_t &value) override {
114 auto t = attr_to_std<std::tuple<ConfObjectRef, Args...>>(value);
115 obj_ = std::get<0>(t);
116 set_args_impl(t, std::index_sequence_for<Args...>{});
117 }
118
120 // The allocated pointer is deleted after the function call is invoked
121 return new MemberFunctionCall<Class, Args...>(*this);
122 }
123
124 attr_value_t get_value() override {
125 auto rest = std::tuple_cat(std::make_tuple(obj_), args_);
126 return std_to_attr(std::make_pair(name_, rest));
127 }
128
129 private:
130 void invoke() override {
131 if (!obj_) {
132 throw std::invalid_argument {
133 "Cannot call class member function without class instance"
134 };
135 }
136 invoke_impl(std::index_sequence_for<Args...>{});
137 }
138
139 // Helper function to unpack the tuple and call the function
140 template<std::size_t... I>
141 void invoke_impl(std::index_sequence<I...>) {
142 (from_obj<Class>(obj_)->*func_)(std::get<I>(args_)...);
143 }
144
145 // Helper function to return a tuple by removing the first item
146 template <std::size_t... Is>
147 void set_args_impl(const std::tuple<ConfObjectRef, Args...> &input_tuple,
148 std::index_sequence<Is...>) {
149 args_ = std::make_tuple(std::get<Is + 1>(input_tuple)...);
150 }
151
152 MemberFunctionType func_;
153 std::string name_;
154 ConfObjectRef obj_;
155 std::tuple<Args...> args_;
156};
157
158template<typename... Args>
159constexpr void check_function_call(void(*func)(Args...)) {}
160
161class BankInterface;
162class RegisterInterface;
163class FieldInterface;
164template<typename Class, typename... Args>
165constexpr void check_function_call(void(Class::*func)(Args...)) {
166 static_assert(std::is_base_of<ConfObject, Class>::value
167 || std::is_base_of<BankInterface, Class>::value
168 || std::is_base_of<RegisterInterface, Class>::value
169 || std::is_base_of<FieldInterface, Class>::value,
170 "Only class derived of ConfObject/BankInterface/"
171 "RegisterInterface/FieldInterface supports the after call");
172}
173
174// Helper function to create a Functional object with deduced types
175template<typename... Args>
176constexpr auto make_function_call(void(*func)(Args...),
177 const std::string &name) {
178 return new FunctionCall<Args...>(func, name);
179}
180
181// Helper function to create a MemberFunctionCall object with deduced types
182template<typename Class, typename... Args>
183constexpr auto make_function_call(void (Class::*func)(Args...),
184 const std::string &name) {
185 return new MemberFunctionCall<Class, Args...>(func, name);
186}
187
188class AfterEvent : public Event {
189 public:
190 using Event::Event;
191
192 // EventInterface
193 void callback(void *data) override;
194 attr_value_t get_value(void *data) override;
195 void *set_value(attr_value_t value) override;
196
197 void remove(void * = nullptr) const;
198 void post(double seconds, void *data = nullptr);
199 void post(cycles_t cycles, void *data = nullptr);
200
201 private:
202 void checkSetValueFormat(const attr_value_t &value);
203};
204
205template <typename T>
207 public:
209 : obj_(obj), after_event(obj, event_cls) {}
210
211 // return EventInfo that can be used to register the event on class T
212 static EventInfo afterEventInfo(const std::string &name = "after_event") {
213 return {
214 name, Sim_EC_No_Flags, &event_cls,
215 EVENT_HELPER(T, after_event, callback),
216 EVENT_HELPER(T, after_event, destroy),
217 EVENT_HELPER(T, after_event, get_value),
218 EVENT_HELPER(T, after_event, set_value),
219 EVENT_HELPER(T, after_event, describe)
220 };
221 }
222
223 // AfterInterface
224 void schedule(double seconds, const std::string &name,
225 const attr_value_t &args) override {
226 auto *iface = get_iface(name);
227 if (iface) {
228 iface->set_args(args);
229 after_event.post(seconds, iface);
230 }
231 }
232 void schedule(cycles_t cycles, const std::string &name,
233 const attr_value_t &args) override {
234 auto *iface = get_iface(name);
235 if (iface) {
236 iface->set_args(args);
237 after_event.post(cycles, iface);
238 }
239 }
240 void cancel_all() override {
242 }
243
244 static event_class_t *event_cls;
245
246 protected:
247 ConfObject *obj_ {nullptr};
249
250 private:
251 // Get AfterCallInterface by name with the arguments configured
252 AfterCallInterface *get_iface(const std::string &name) {
253 auto *iface = AfterCall::findIface(name);
254 if (iface == nullptr) {
256 obj_->obj(), 0,
257 std::string("After call (" + name + ") needs to be "
258 "registered by REGISTER_AFTER_CALL or "
259 "REGISTER_REG_BANK_AFTER_CALL first"));
260 return nullptr;
261 }
262 return iface->make_copy();
263 }
264};
265
266template <typename T>
267event_class_t *EnableAfterCall<T>::event_cls = nullptr;
268
269} // namespace simics
270
271#define FUNC_AND_NAME(f) f, #f
272
273#define REGISTER_AFTER_CALL(f) \
274 simics::AfterCall::addIface(simics::make_function_call(FUNC_AND_NAME(f)));
275
276#define AFTER_CALL(dev, t, f, ...) { \
277 simics::check_function_call(f); \
278 auto *iface = dynamic_cast<simics::AfterInterface *>(dev); \
279 if (iface == nullptr) { \
280 std::cerr << "The first argument to the AFTER_CALL does " \
281 << "not implement AfterInterface*" \
282 << std::endl; \
283 } else { \
284 iface->schedule(t, std::string(#f) + typeid(f).name(), \
285 simics::AttrValue(simics::std_to_attr( \
286 std::forward_as_tuple(__VA_ARGS__)))); \
287 } \
288}
289#endif
Definition: after-interface.h:27
Definition: after.h:38
static void removeIface(AfterCallInterface *iface)
static void addIface(AfterCallInterface *iface)
static AfterCallInterface * findIface(const std::string &name)
Definition: after.h:188
void callback(void *data) override
Called when the event expires.
void remove(void *=nullptr) const
void post(double seconds, void *data=nullptr)
void post(cycles_t cycles, void *data=nullptr)
void * set_value(attr_value_t value) override
Called to convert a configuration value into event data.
attr_value_t get_value(void *data) override
Called to convert the event data into a value that can be saved in a configuration.
Definition: after-interface.h:44
Represents Simics C type conf_object_t.
Definition: conf-object.h:38
Base class for all Simics configuration objects.
Definition: conf-object.h:126
ConfObjectRef obj() const
Return a ConfObjectRef represents this object.
Definition: conf-object.h:137
Definition: after.h:206
void schedule(cycles_t cycles, const std::string &name, const attr_value_t &args) override
Definition: after.h:232
ConfObject * obj_
Definition: after.h:247
AfterEvent after_event
Definition: after.h:248
static event_class_t * event_cls
Definition: after.h:244
void cancel_all() override
Definition: after.h:240
void schedule(double seconds, const std::string &name, const attr_value_t &args) override
Definition: after.h:224
static EventInfo afterEventInfo(const std::string &name="after_event")
Definition: after.h:212
EnableAfterCall(ConfObject *obj)
Definition: after.h:208
The Event class allows users to define callbacks that will be executed after a specified delay.
Definition: event.h:79
Event(ConfObject *obj, event_class_t *ev)
Definition: after.h:51
FunctionCall(FunctionType func, const std::string &name)
Definition: after.h:55
void(*)(Args...) FunctionType
Definition: after.h:53
std::string name() const override
Definition: after.h:59
AfterCallInterface * make_copy() override
Definition: after.h:67
attr_value_t get_value() override
Definition: after.h:72
void set_args(const attr_value_t &value) override
Definition: after.h:63
Definition: after.h:97
void(Class::*)(Args...) MemberFunctionType
Definition: after.h:99
AfterCallInterface * make_copy() override
Definition: after.h:119
attr_value_t get_value() override
Definition: after.h:124
std::string name() const override
Definition: after.h:105
MemberFunctionCall(MemberFunctionType func, const std::string &name)
Definition: after.h:101
void set_args(const attr_value_t &value) override
Definition: after.h:113
#define EVENT_HELPER(cls, m, f)
Definition: event-helper.h:28
#define SIM_LOG_ERROR_STR(obj, group, str)
Definition: log.h:39
Definition: after-bank.h:33
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
std::enable_if< std::is_enum< T >::value, T >::type attr_to_std(attr_value_t src)
Function transforms Simics attr_value_t to C++ enum type.
Definition: attribute-traits.h:207
constexpr auto make_function_call(void(*func)(Args...), const std::string &name)
Definition: after.h:176
constexpr void check_function_call(void(*func)(Args...))
Definition: after.h:159
Definition: event.h:47