Philipp, Everybody,
I have worked through Philipp's sc_vector proposal. I will share some 
examples with you, starting with the most basic features, then showing the 
clever cases. I have a few comments/questions, highlighted below.
Firstly, you can construct vectors of modules, ports, exports, and 
channels, e.g.
        sc_vector<my_module> my_vec;  // vector-of-modules
        sc_vector<sc_inout<int> >   ports;   // vector-of-ports
        sc_vector<sc_port<i_f> > ports;      // vector-of-user-defined 
ports
        sc_vector<sc_signal<int> > sigs;   // vector-of primitive channels
Secondly, you can set the size of the port either at construction time or 
deferred until later:
Either
        : ports("ports", N)      // "ports" used as the prefix for the 
string name, 
or
        : ports("ports")
        { 
                  ports.init(N);  // N is the size of the vector - cannot 
be modified once it has been set
Thirdly, you can access the vector elements using the size(), operator[], 
and at() methods, e.g.
        for (unsigned int i = 0; i < ports.size(); i++) 
                ports[i]->method();
        m1->ports[i].bind( sigs[i] );  // ports and sigs are both 
sc_vectors
We are constraining the elements to be sc_objects. In each case, the 
elements of the sc_vector are all children of the containing module or 
process instance, so are picked up by
        std::vector<sc_object*> children = obj->get_child_objects();
This is all very natural and as-expected.
Then we add a few wrinkles. It is possible to bind a vector-of-ports to a 
vector-of-channels directly, with no explicit loop, e.g.
        module_inst->ports.bind( sigs );  // ports is a vector-of-ports 
and sigs is a vector-of-sigs
Very nice. It is also possible to bind just a subset of the 
vector-of-ports, then come back for another pass later:
        typedef sc_vector<sc_inout<int> > port_type;
        port_type::iterator it;
        // Bind upper half of ports vector to hi_sigs 
        it = module_inst->ports.bind( hi_sigs.begin(), hi_sigs.end() ); // 
hi_sigs.size() < ports.size()
 
        // Bind lower half of ports vector to lo_sigs 
        it = module_inst->ports.bind( lo_sigs.begin(), lo_sigs.end(), it); 
  // Notice binding starts from position 'it' within ports vector
The above syntax - having bind return the position of the 1st unbound 
element - seems a little arcane to me. Are we all okay with it?
But sometimes, rather than having a vector-of-ports, you might have a 
vector-of-modules each containing a single port. In this case it is 
possible to treat these ports distributed across multiple modules as one 
vector, using sc_view. For example:
        struct Initiator1: sc_module
        {
                sc_port<i_f> port;
                ...
        struct Target: public sc_module, private i_f
        {
                sc_export<i_f> xp;
                ...
        sc_vector<Initiator1> initiator_vec;
        sc_vector<Target>     target_vec;
        sc_view(initiator_vec, &Initiator1::port).bind( sc_view
(target_vec, &Target::xp) );
In the above
        sc_view(initiator_vec, &Initiator1::port)  creates a 
vector-of-ports
        sc_view(target_vec, &Target::xp)  creates a vector-of-exports
        .bind()  does a vector-to-vector bind
The semantics are very nice, but I am not particularly happy with the name 
sc_view, because this is not suggestive of what is actually happening, 
that is, gathering together a vector from a set of elements distributed 
across another vector. Is there a precedent for the name sc_view, Phillip? 
How about something like sc_gather or sc_make_vector or sc_vectorize 
instead?
It is possible to extract a std::vector of elements from any sc_vector, 
e.g.
        std::vector<sc_object*> elements;
        elements = ports.get_elements();
        elements = sc_view(initiator_vec, 
&Initiator1::port).get_elements();
Finally, in the special case of a vector-of-modules, it is possible to 
pass extra arguments to the module constructor, e.g.
        struct my_module: sc_module
        {
                 my_module(sc_module_name n, string weird_arg ) {...}
                ...
        ...
        sc_vector<my_module> my_vec;
 
        struct my_module_creator
        {
                my_module_creator( string arg ) : weird_arg(arg) {}
 
                my_module* operator() (const char* name, size_t)
                {
                        return new my_module(name, weird_arg );
                }
                string weird_arg;
        };
        ...
        my_vec.init(N, my_module_creator("The Creator"));
This works, but creating the function object feels like having to jump 
through hoops. I think regular users are going to find it confusing. Can 
we do any clever tricks to make it easier to use?
Thanks,
John A
 
-- This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean.Received on Tue Nov 9 05:06:40 2010
This archive was generated by hypermail 2.1.8 : Tue Nov 09 2010 - 05:06:43 PST