Jump to content

Automation for probing port connectivity


David Black

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
Link to comment
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.

Link to comment
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.

Link to comment
Share on other sites

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...