Jump to content

Recommended Posts

Posted

Hello,
I'm really new on SystemC and TLM (you will notice that) and I want to design a component , with a variable number of two different kind of target sockets. Every of these sockets have a vector mem , defined as a global variable inside MyModule whose value is increment at each transaction incoming from a initiator socket to that specific socket.
So i wrote

template<unsigned int N_TARGETS>   
struct MyModule: sc_module
{
 enum { SIZE = 100 };
 int mem[size];  //should I implement it has a matrix mem[N*2][size]? read below
 tlm_utils::simple_target_socket<MyModule>* multiple_socket[N];
 tlm_utils::simple_target_socket<MyModule>* multiple_socket2[N];
 .....
}

This way when I'll instanciate a object MyModule , I'll simple write Mymodule <N>  module   to have it with the two vectors of  N target socket.

Then on the constructor of MyModule i write

 

 

SC_CTOR(MyModule) {
for (unsigned int i = 0; i < N; i++){        
char txt[20];     
sprintf(txt, "socket_%d", i);
multiple_socket[i]= new tlm_utils::simple_target_socket<MyModule>(txt) ;         
multiple_socket[i]-> register_b_transport(this, &MyModule::b_transport,i);
multiple_socket2[i]= new tlm_utils::simple_target_socket<MyModule>(txt) ;
multiple_socket2[i]-> register_b_transport(this, &MyModule::b_transport,i); 
          }
}
 

 

 

My problem is to implement b_transport method in order to  :

  • for every incoming transaction from a initiator socket , write the correct memory area for the correct socket 
  • implement the mem vector : should I have to implement the mem vector as a matrix mem[N*2] in order to simulate in a sense the different memory register of each socket? 

Thank you for the patience 
Giovanni

Posted

Hi Giovanni,

 

Every of these sockets have a vector mem , defined as a global variable inside MyModule whose value is increment at each transaction incoming from a initiator socket to that specific socket.

 

I don't fully understand the modelling intent here. What is the relation between SIZE and N?

What do you mean by "whose value is incremented"? Do the two socket arrays each share the same memory segment?

If you have one socket and one "memory" bundled together, I would suggest to build (or use an existing) TLM-2 memory module, which already provides the required transport implementation. Then you can use an array of memory modules, instead of arrays of sockets and memories. Your requirements may vary, of course.

From a source code perspective, you should definitely use sc_vector (SystemC 2.3.0) here.

 

template<unsigned int N_TARGETS>   
struct MyModule: sc_module
{
 enum { SIZE = 100 };
 int mem[size];  //should I implement it has a matrix mem[N*2][size]? read below
 tlm_utils::simple_target_socket<MyModule>* multiple_socket[N];
 tlm_utils::simple_target_socket<MyModule>* multiple_socket2[N];
 .....
} 

 

First remark: If you want to distinguish the incoming socket within your b_transport function, you should use a simple_target_socket_tagged<MyModule>. Within your constructor, you already pass the index to the register_b_transport function, which is only supported by the tagged sockets.


Following the example from https://complex.offis.de/documents/doc_details/29, your module would look like:

template<unsigned int N_TARGETS>   
SC_MODULE( MyModule ){
 enum { SIZE = 100 };
 int mem[size];  //should I implement it has a matrix mem[N*2][size]? read below

 typedef tlm_utils::simple_target_socket_tagged<MyModule> socket_type;
 sc_core::sc_vector< socket_type > multiple_socket;
 sc_core::sc_vector< socket_type > multiple_socket2;
 .....
}

The constructor would then look like:

SC_CTOR(MyModule)
  : multiple_socket("socket") 
  , multiple_socket2("socket2") // these names are not very descriptive...
{
   // initialise sockets with sizes and "custom creator"
   multiple_sockets.init ( N, sc_bind( &MyModule::create_socket, this, 0, _1, _2 ) );
   multiple_sockets2.init( N, sc_bind( &MyModule::create_socket, this, 1, _1, _2 ) );
}

// custom creator function (first parameter is the "socket vector number")
socket_type* create_socket( int vec_no, const char* nm, size_t idx )
{
  socket_type* socket_p = new socket_type(nm);
  int tag = (idx*2)+vec_no; // store vector number in LSB of tag
  socket_p->register_b_transport( this, &MyModule::b_transport, tag );
  return socket_p;
}

Now, you can distinguish the incoming socket by the unique "tag", passed to the b_transport function.

 

My problem is to implement b_transport method in order to  :

  • for every incoming transaction from a initiator socket , write the correct memory area for the correct socket 
  • implement the mem vector : should I have to implement the mem vector as a matrix mem[N*2] in order to simulate in a sense the different memory register of each socket?

 

The b_transport function could look like the following:

void b_transport( ..., int id )
{
 int vec_no  = id%2;
 int vec_idx = id/2;
  // do whatever you need with your memories, related to vec_no and vec_idx
}

Since I haven't fully understood your intent, it's hard to comment on the "correct" implementation of the memory arrays.

 

Greetings from Oldenburg,

  Philipp

Posted

Hi Philipp, 
first of all thank you for your answer and sorry if I'm not been clear.

The module I want to design is basically a Power Generator that provide energy to another module, an Appliance, a power consumer. The module Appliance contain also a battery to provide extra energy, and a Processing Unit in order to switch between the two power sourcess (Battery or Power Generator). The Battery is also connected to the PowerGenerator in order to recharge.
So for each Appliance the Power Generator have to "reserve" two sockets:

  • 1 target socket (let's call it app_socket) to provide energy to the Appliance request
  • 1 target socket (let's call it batt_socket) to provide energy to the Appliance's battery energy request

The request is expressed , in a very simple way , as a request on x energy unit (e.g 4 energy units).
Every socket has a register (the mem vector in my code) of fixed size ( the SIZE) and for each request :

  • if it's a Appliance request of x energy unit ---> increment of x the value of the register of  app_socket reserved to that appliance 
  • if it's an Appliance's battery request of x energy unit ---> increment of x the value of the register of batt_socket reserved to the battery of that appliance

So every sockey has his internal memory , independent from the other socket.

For design requirement, I've to implement sockets and memories in my Power Generator 
So my intent was to create a customizable Power Generator, where in the constructor you can provide the number of Appliance of the system (N in my code) in order to create a PowerGenerator with the right number of sockets.
My tutor provide me an example of code for a Power Generator with only one socket (so with just one mem vector), which b_transport method is implemented this way


 
virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay )
  {
    tlm::tlm_command cmd = trans.get_command();
    sc_dt::uint64    adr = trans.get_address() / 4;
    unsigned char*   ptr = trans.get_data_ptr();
    unsigned int     len = trans.get_data_length();
    unsigned char*   byt = trans.get_byte_enable_ptr();
    unsigned int     wid = trans.get_streaming_width();


    if (adr >= sc_dt::uint64(SIZE) || byt != 0 || len > 4 || wid < len)
      SC_REPORT_ERROR("TLM-2", "Target does not support given generic payload transaction");


    if ( cmd == tlm::TLM_WRITE_COMMAND ){
      memcpy(&curr_rq_val, ptr, len);
      int index = sc_time_stamp().value() / 10000;
      cout << sc_time_stamp() << " :: " << "PowerGenerator" << " :: " << "CurrentIndex" << " :: " << index << "\n";
      mem[index] = curr_rq_val;
      overall_consumption += curr_rq_val;
      cout << sc_time_stamp() << " :: " << "PowerGenerator" << " :: " << "SOCKET_0" << " :: " << "ENERGY_REQUEST_RESPONSE"  << " :: " << mem[index] << "\n";
      int current_drain = mem[index]
      cout << sc_time_stamp() << " :: " << "PowerGenerator" << " :: " << "CURRENT_DRAIN" << " :: {" << current_drain << "}\n";
      cout << sc_time_stamp() << " :: " << "PowerGenerator" << " :: " << "OVERALL_DRAIN" << " :: {" << overall_consumption << "}\n";


    }


    // Obliged to set response status to indicate successful completion
    trans.set_response_status( tlm::TLM_OK_RESPONSE );
  }
 

so the socket will register to this b_transport.
My original dubt was : if I have multiple socket I have to register them to a b_transport method and  I need a way to specify that the transaction has to write the requested value in the correct mem vector of the correct socket.

Giovanni

Posted

I've decided to try the sc_vector solution that you propose . I don't understand the use of the placeholders _1 , _2  on init function , and how can I implement my b_transport function.
I use the sc_time_stamp to get the index of the mem array while you're sugesting to use int vec_idx = id/2;


Giovanni

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