Jump to content
David Black

Automation for probing port connectivity

Recommended Posts

Note: This is somewhat of an expert question.

I am considering how best to probe a SystemC design to determine connectivity. My goal is to be able to automatically determine how ports are connected at end-of-elaboration or later. My first inclination was to do something like:

std::cout << "Connection from " << myport.name() << " to " << myport->name() << std::endl;

Just to be clear, myport.name() provides the path to the port itself; whereas, myport->name() should provide the path to the channel that the port is connected to.

However the above requires all channels and interfaces to implement the method name(), which is not currently the case. The implementation would simply be:

const char* Channel::name( void ) const
{
  return sc_object::name();
}

I am first looking to see if anybody has a current solution that does not require modification of the standard. I don't think it exists, but I could be overlooking something.

Edited by David Black
Clarification

Share this post


Link to post
Share on other sites

I think you have answered your question yourself ūüôā

Quote

However the above requires all channels and interfaces to implement the method¬†name(), which is not currently the case.¬†ÔĽŅ

In practice however most channels inherit sc_object, so they have method name(). So you can do something like this (print_connections method):

#include <systemc.h>

struct void_if : sc_interface { };

struct test : sc_module , void_if {

    struct submodule : sc_module , void_if {
        sc_export<void_if> SC_NAMED(void_export);
        SC_CTOR(submodule) { void_export.bind(*this); }
    } SC_NAMED(sub);

    struct not_sc_object : void_if {
    } non_sc_obj;

    sc_vector<sc_port<void_if>> SC_NAMED(ports, 3);

    SC_CTOR(test) {
        ports[0].bind(*this);
        ports[1].bind(sub.void_export);
        ports[2].bind(non_sc_obj);
    }

    void print_connections(const sc_object * cur, std::string padding ) const {
        cout << padding << cur->name();

        const sc_interface * binded_iface = nullptr;
        if (auto exp = dynamic_cast<const sc_export_base*>(cur)) {
            cout << " (export) ";
            binded_iface = exp->get_interface();
        }
        else if (auto port = dynamic_cast<const sc_port_base*>(cur)) {
            cout << " (port) ";
            binded_iface = port->get_interface();
        }

        if (binded_iface) {
            cout << " bound to ";
            if (auto binded_obj = dynamic_cast<const sc_object*>(binded_iface)) {
                cout << binded_obj->name();
            } else {
                cout << "not an sc_object";
            }
        }

        cout << "\n";

        for (auto *child : cur->get_child_objects()) {
            print_connections(child, padding + "   ");
        }
    }

    void start_of_simulation() override
    {
        for (auto * obj : sc_get_top_level_objects()) {
            print_connections ( obj , "");
        }
    }
};


int sc_main(int, char**) {
    test test_inst{"test_inst"};
    sc_start();
    return 0;
}

Will print:

test_inst
   test_inst.sub
      test_inst.sub.void_export (export)  bound to test_inst.sub
   test_inst.ports
   test_inst.ports_0 (port)  bound to test_inst
   test_inst.ports_1 (port)  bound to test_inst.sub
   test_inst.ports_2 (port)  bound to not an sc_object

 

Sometimes you also want to print hierarchical port-to-port connections (instead of port-to-interface) .  This I think is not possible.  For our internal uses we had modified Accellera SystemC kernel to preserve information about hierarchical connections.

Share this post


Link to post
Share on other sites

Actually, I was very close to the solution you provided, and it provides some of the solution. The hierarchical is not a problem for my needs. I am having problems getting my TLM sockets to report properly. I only need the initiator sockets.

Thank you.

 

Share this post


Link to post
Share on other sites
On 12/29/2018 at 2:10 AM, David Black said:

I am having problems getting my TLM sockets to report properly.

Yes, with TLM sockets this won't work well: for example classes implementing TLM interfaces inside tlm_utils::* sockets do not inherit from sc_object. So you will have "not an sc_object" reported if you call print_connections function on some generic TLM model.

In general such a problem is a subset of "serialization" problem, which is not possible to solve in standard C++. Because C++ wants to be "zero cost" and does not provide dynamic introspection capabilities.  

You can solve the problem radically by utilizing C++ compiler internals. By doing so you can implement whatever functionality you want (usually people want the same features they have in  Verilog/VHDL tools). I'm not sure, but probably you can have this feature of dumping connectivity from commercial SystemC tools.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×