Jump to content

Determining the most specific port class of an object and its associated signals at runtime


cma

Recommended Posts

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.

Link to comment
Share on other sites

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>

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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

 

Link to comment
Share on other sites

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!

Link to comment
Share on other sites

  • 2 weeks later...

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...