cma Posted March 28 Report Share Posted March 28 Dear SystemC Forum user, In a current project, I am traversing a given SystemC object graph in order to visualize it later. To accomplish this, I am using the SystemC API, as described in Chapter "The object in question" of Ainsley's [Here's Exactly What You Can Do with the New SystemC Standard!](https://www.doulos.com/media/1599/new_systemc_standard.pdf). Specifically, I am using the `get_child_objects()` and `get_parent_object()` methods of the `sc_object` class. The class type of each object can be determined using the `kind()` method, which returns a string with the class type. However, to generate a detailed object graph and determine which signals are bound to a port and if the port is an input, output or input-output port, this information is insufficient. Each object must be cast to a specific port class in order to determine which signals are bound to it. Because specific port classes have template parameters, there are an unlimited number of possibilities for which specific port class an object belongs to. Without modifying the current SystemC API, the only option I can think of is to cast objects of the `sc_object` class into all possible port classes to determine which specific class type a port belongs to. However, this method is highly repetitive and not suitable if, for example, custom data types are also to be considered at the ports. To circumvent this issue, I have extended the SystemC port class using the visitor pattern to enable specialized port classes to expose their information at runtime through the invocation of a virtual method, thereby allowing me to determine which specific port class an object belongs to. This was achieved by implementing a method, `accept(port_visitor& visitor)`, in the base class `sc_port_base`, which is overridden in all specialized classes. This method will be called on the base class and through the nature of virtual methods will invoke the most specific implementation on the derived classes. Within the method implementation, all signals are cast to the type of the port class (this information is available within the class declaration) and saved through a call to `visitor.visit(this, signals)`. The only difference between the method implementations in the various classes is that a different `visit` method is called depending on whether the port is an input port, output port, or bidirectional port. My question is whether this implementation is necessary and appropriate, or if there might be a solution I have overlooked. Thank you for your time and reading. Quote Link to comment Share on other sites More sharing options...
Eyck Posted March 29 Report Share Posted March 29 If you stay in C++ this is the only solution. But by modifying the SystemC kernel you loose standards compatibility. If you can switch to python there is PySysC (https://github.com/accellera-official/PySysC) which allows to inspect data types at runtime. cma 1 Quote Link to comment Share on other sites More sharing options...
Andy Goodrich Posted March 29 Report Share Posted March 29 I think you can get most of what you need by using type_info and typeid(), and things like the get_interface() method. For instance, given the program: #include "systemc.h" #include <cxxabi.h> std::string type_name( const sc_object* var_p ) { int status = -1; return abi::__cxa_demangle(typeid(*var_p).name(),NULL, NULL, &status); } SC_MODULE(X) { sc_in<double> a; sc_inout<sc_uint<18> > b; sc_out<uint64> c; sc_port<sc_signal<int> > d; SC_CTOR(X) { } }; int sc_main(int argc, char* argv[]) { X x("x"); std::vector<sc_object*> child_objects; child_objects = x.get_child_objects(); for ( size_t object_i = 0; object_i < child_objects.size(); ++object_i ) { cout << type_name(child_objects[object_i]) << endl; } return 0; } The output is: SystemC 2.4.0_pub_rev_20191203-Accellera --- Mar 19 2023 12:27:55 Copyright (c) 1996-2019 by all Contributors, ALL RIGHTS RESERVED sc_core::sc_in<double> sc_core::sc_inout<sc_dt::sc_uint<18> > sc_core::sc_out<unsigned long long> sc_core::sc_port<sc_core::sc_signal<int, (sc_core::sc_writer_policy)0>, 1, (sc_core::sc_port_policy)0> Quote Link to comment Share on other sites More sharing options...
cma Posted March 30 Author Report Share Posted March 30 17 hours ago, Andy Goodrich said: I think you can get most of what you need by using type_info and typeid(), and things like the get_interface() method. For instance, given the program: #include "systemc.h" #include <cxxabi.h> std::string type_name( const sc_object* var_p ) { int status = -1; return abi::__cxa_demangle(typeid(*var_p).name(),NULL, NULL, &status); } SC_MODULE(X) { sc_in<double> a; sc_inout<sc_uint<18> > b; sc_out<uint64> c; sc_port<sc_signal<int> > d; SC_CTOR(X) { } }; int sc_main(int argc, char* argv[]) { X x("x"); std::vector<sc_object*> child_objects; child_objects = x.get_child_objects(); for ( size_t object_i = 0; object_i < child_objects.size(); ++object_i ) { cout << type_name(child_objects[object_i]) << endl; } return 0; } The output is: SystemC 2.4.0_pub_rev_20191203-Accellera --- Mar 19 2023 12:27:55 Copyright (c) 1996-2019 by all Contributors, ALL RIGHTS RESERVED sc_core::sc_in<double> sc_core::sc_inout<sc_dt::sc_uint<18> > sc_core::sc_out<unsigned long long> sc_core::sc_port<sc_core::sc_signal<int, (sc_core::sc_writer_policy)0>, 1, (sc_core::sc_port_policy)0> Thank you for your reply. Unfortunately I don't see how this would help me. How am I able with this information to cast the port objects from sc_object* to their most specific port class? `get_interface` onl returns the first bound channel and operator[] which returns the bound channels is only implemented in the derived classes. Quote Link to comment Share on other sites More sharing options...
Andy Goodrich Posted March 30 Report Share Posted March 30 You should at least be able to get the derived port type and the derived type of a port's interface. Here is a modified version the previous program: #include "systemc.h" #include <cxxabi.h> int hash_code( const sc_object* var_p ) { return typeid(*var_p).hash_code(); } std::string object_type_name( const sc_object* var_p ) { int status = -1; return abi::__cxa_demangle(typeid(*var_p).name(),NULL, NULL, &status); } std::string interface_type_name( const sc_interface* var_p ) { int status = -1; return abi::__cxa_demangle(typeid(*var_p).name(),NULL, NULL, &status); } SC_MODULE(X) { sc_in<double> a; sc_inout<sc_uint<18> > b; sc_out<uint64> c; sc_port<sc_signal<int> > d; SC_CTOR(X) { } }; int sc_main(int argc, char* argv[]) { sc_signal<double> sig_a; X x("x"); x.a(sig_a); std::vector<sc_object*> child_objects; // Grab the sc_objects within module 'x': child_objects = x.get_child_objects(); // Get the interface on port 'a' and "type" it: sc_port_base* port_p = dynamic_cast<sc_port_base*>(child_objects[0]); sc_interface* interface_p = port_p->get_interface(); std::string type = interface_type_name(interface_p); std::cout << "interface is an " << type << endl; // Loop through the objects in the module and determine their port type: for ( size_t object_i = 0; object_i < child_objects.size(); ++object_i ) { std::string type = object_type_name(child_objects[object_i]); cout << type; if ( std::string::npos != type.find("sc_inout") ) { cout << " is an sc_inout" << endl; } else if ( std::string::npos != type.find("sc_in") ) { cout << " is an sc_in" << endl; } else if ( std::string::npos != type.find("sc_out") ) { cout << " is an sc_out" << endl; } else if ( std::string::npos != type.find("sc_port") ) { cout << " is an sc_port" << endl; } else { cout << " is an unknown" << endl; } } return 0; } The output is: SystemC 2.4.0_pub_rev_20191203-Accellera --- Mar 19 2023 12:27:55 Copyright (c) 1996-2019 by all Contributors, ALL RIGHTS RESERVED interface is an sc_core::sc_signal<double, (sc_core::sc_writer_policy)0> sc_core::sc_in<double> is an sc_in sc_core::sc_inout<sc_dt::sc_uint<18> > is an sc_inout sc_core::sc_out<unsigned long long> is an sc_out sc_core::sc_port<sc_core::sc_signal<int, (sc_core::sc_writer_policy)0>, 1, (sc_core::sc_port_policy)0> is an sc_port cma 1 Quote Link to comment Share on other sites More sharing options...
cma Posted March 31 Author Report Share Posted March 31 18 hours ago, Andy Goodrich said: You should at least be able to get the derived port type and the derived type of a port's interface. Here is a modified version the previous program: #include "systemc.h" #include <cxxabi.h> int hash_code( const sc_object* var_p ) { return typeid(*var_p).hash_code(); } std::string object_type_name( const sc_object* var_p ) { int status = -1; return abi::__cxa_demangle(typeid(*var_p).name(),NULL, NULL, &status); } std::string interface_type_name( const sc_interface* var_p ) { int status = -1; return abi::__cxa_demangle(typeid(*var_p).name(),NULL, NULL, &status); } SC_MODULE(X) { sc_in<double> a; sc_inout<sc_uint<18> > b; sc_out<uint64> c; sc_port<sc_signal<int> > d; SC_CTOR(X) { } }; int sc_main(int argc, char* argv[]) { sc_signal<double> sig_a; X x("x"); x.a(sig_a); std::vector<sc_object*> child_objects; // Grab the sc_objects within module 'x': child_objects = x.get_child_objects(); // Get the interface on port 'a' and "type" it: sc_port_base* port_p = dynamic_cast<sc_port_base*>(child_objects[0]); sc_interface* interface_p = port_p->get_interface(); std::string type = interface_type_name(interface_p); std::cout << "interface is an " << type << endl; // Loop through the objects in the module and determine their port type: for ( size_t object_i = 0; object_i < child_objects.size(); ++object_i ) { std::string type = object_type_name(child_objects[object_i]); cout << type; if ( std::string::npos != type.find("sc_inout") ) { cout << " is an sc_inout" << endl; } else if ( std::string::npos != type.find("sc_in") ) { cout << " is an sc_in" << endl; } else if ( std::string::npos != type.find("sc_out") ) { cout << " is an sc_out" << endl; } else if ( std::string::npos != type.find("sc_port") ) { cout << " is an sc_port" << endl; } else { cout << " is an unknown" << endl; } } return 0; } The output is: SystemC 2.4.0_pub_rev_20191203-Accellera --- Mar 19 2023 12:27:55 Copyright (c) 1996-2019 by all Contributors, ALL RIGHTS RESERVED interface is an sc_core::sc_signal<double, (sc_core::sc_writer_policy)0> sc_core::sc_in<double> is an sc_in sc_core::sc_inout<sc_dt::sc_uint<18> > is an sc_inout sc_core::sc_out<unsigned long long> is an sc_out sc_core::sc_port<sc_core::sc_signal<int, (sc_core::sc_writer_policy)0>, 1, (sc_core::sc_port_policy)0> is an sc_port Thank you, Andy. I appreciate it! Quote Link to comment Share on other sites More sharing options...
Eyck Posted April 14 Report Share Posted April 14 Please be aware: cxxabi.h is a GCC specific implementation and will quite likely not work with MSVC or Clang cma 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.