Jump to content

Help me understand this TLM example ??


Recommended Posts

could any one help me understand this TLM example for a simple counter .....

 

// TLM counter
// compiler: Visual C++ 2008 Express Edition
//
#include <stdio.h>
#include <systemc.h>
#include "tlm.h"
#include "tlm_utils/simple_initiator_socket.h"
#include "tlm_utils/simple_target_socket.h"
using namespace tlm;
using namespace tlm_utils;
//
// C++ counter
//
unsigned int counter(unsigned int cnt)
{
   return (cnt+1);
}
//
// SystemC counter module
//
class counter_module : public sc_module
{
   SC_HAS_PROCESS(counter_module);
   virtual void increment_request_transport(tlm_generic_payload& tx, sc_time& dt);
   public:
      simple_target_socket<counter_module> increment_socket;
   private:
      unsigned int cnt;
   public:
      counter_module(sc_module_name nm) : sc_module(nm),
         increment_socket("increment_socket")
      {
         increment_socket.register_b_transport(this, &counter_module::increment_request_transport);
	     cnt=0;
      }
   const char* hdl_name() const { return "counter_module"; }
};
//
// Transport Handler
//
void counter_module::increment_request_transport(tlm_generic_payload& tx, sc_time& dt)
{
   if(tx.get_command() == TLM_READ_COMMAND)
   {
      cnt = counter(cnt);
      tx.set_data_length(4);
	  unsigned char rv[5];
	  rv[0] = cnt & 0xFF;
	  rv[1] = (cnt>>8) & 0xFF;
	  rv[2] = (cnt>>16) & 0xFF;
	  rv[3] = (cnt>>24) & 0xFF;
//cout << " cnt = " << (int)rv[0] << " " << (int)rv[1] << " " << (int)rv[2] << " " << (int)rv[3] << endl;
      tx.set_data_ptr(rv);
      tx.set_response_status(TLM_OK_RESPONSE);
   }
   else if(tx.get_command() == TLM_WRITE_COMMAND) // Reset actually
   {
      cnt = 0;
	  unsigned char rv[5];
	  rv[0] = cnt & 0xFF;
	  rv[1] = (cnt>>8) & 0xFF;
	  rv[2] = (cnt>>16) & 0xFF;
	  rv[3] = (cnt>>24) & 0xFF;
      tx.set_data_length(4);
      tx.set_data_ptr(rv);//conversion from int to char iccurs
      tx.set_response_status(TLM_OK_RESPONSE);
   }
   else
      tx.set_response_status(TLM_ADDRESS_ERROR_RESPONSE);
}
//
// Stimulus generator
//
class stimulus: public sc_module
{
   SC_HAS_PROCESS(stimulus);
   public:
      simple_initiator_socket<counter_module> read_increment;
      tlm_generic_payload tx;
      void run();

      void reset_counter();
      unsigned int read_counter();

   stimulus(sc_module_name nm) :
      sc_module(nm),
      read_increment("read_increment")
   {
      SC_THREAD(run);
   }
   const char* hdl_name() const { return "stimulus"; }
};
//
// Stimulus main process
//
void stimulus::run()
{
   reset_counter();
   wait(1, SC_NS);
   for(int i=1; i<22; i++)
   {
      cout << "Counter = " << read_counter() << " at cycle " << i << endl;
      wait(1, SC_NS);
   }
   reset_counter();
   wait(1, SC_NS);
   for(int i=23; i<100; i++)
   {
      cout << "Counter = " << read_counter() << " at cycle " << i << endl;
      wait(1, SC_NS);
   }
   sc_stop();
}
//
// Reset counter request
//
void stimulus::reset_counter()
{
   tx.set_address(0);
   unsigned char value[5] = {0,0,0,0,0};
   tx.set_data_ptr(value);
   tx.set_data_length(1);
   tx.set_command(TLM_WRITE_COMMAND);
   sc_time to(SC_ZERO_TIME);
   read_increment->b_transport(tx, to);
   wait(1, SC_NS);
}
//
// Read counter (increment occurs before reading)
//
unsigned int stimulus::read_counter()
{
   unsigned int data;
   tx.set_address(0);
   tx.set_data_length(1);
   sc_time to(SC_ZERO_TIME);
   tx.set_command(TLM_READ_COMMAND);
   read_increment->b_transport(tx, to);
   data = *reinterpret_cast<unsigned int*>(tx.get_data_ptr());
   wait(20, SC_NS);
   return data;
}
//
// Top-level module
//
int sc_main (int argc, char *argv[])
{
   counter_module counter_module_dut("counter_module_dut");
   stimulus stimulus_dut ("stimulus_dut");
   stimulus_dut.read_increment(counter_module_dut.increment_socket);

   sc_start();
   return 0;
}

 

Link to comment
Share on other sites

The increment_request_transport just implements the b_transport interface for this component.  It is registered on the forward path with the simple_target_socket, as you can see in the constructor.  The name of this callback function can be chosen arbitrarily, as you can see (as long as the signature matches).

 

That said, you should not adopt the coding style of this example.  The target is not supposed to modify the data pointer (just its contents).  Even worse, a pointer to a local variable is returned, which just happens to work by chance and may break at any moment (undefined behaviour).

 

/Philipp

Link to comment
Share on other sites

thanks for your reply...

could you help me understand what do you mean by signature matching ...... and

// Reset counter request
//
void stimulus::reset_counter()
{
   tx.set_address(0);
   unsigned char value[5] = {0,0,0,0,0};
   tx.set_data_ptr(value);
   tx.set_data_length(1);
   tx.set_command(TLM_WRITE_COMMAND);
   sc_time to(SC_ZERO_TIME);
   read_increment->b_transport(tx, to);
   wait(1, SC_NS);
}
//
// Read counter (increment occurs before reading)
//
unsigned int stimulus::read_counter()
{
   unsigned int data;
   tx.set_address(0);
   tx.set_data_length(1);
   sc_time to(SC_ZERO_TIME);
   tx.set_command(TLM_READ_COMMAND);
   read_increment->b_transport(tx, to);
   data = *reinterpret_cast<unsigned int*>(tx.get_data_ptr());
   wait(20, SC_NS);
   return data;
}
//

why have they have two different definations for read_counter().....

Link to comment
Share on other sites

  1. You should read up on C++ functions (and overloading) in general to learn about signatures.
  2. In the owning class of the simple_target_socket, a callback is registered instead of an explicit socket binding. 
  3. One function is called reset_counter, the other one read_counter
  4. The stimulus class' socket (called read_increment) is bound in sc_main.

But, as I said, the code is a rather bad example to learn about such basic things.

 

/Philipp

Link to comment
Share on other sites

Ok, that's when you use the Simple Sockets - have a look in the TLM2 documentation (in the SystemC 1666-2011 Language Reference Manual, which you can download from Accellera). There is a summary in there of the utilities that are provided with TLM2, including the "convenience sockets" - see section 16.1

 

regards

Alan

Link to comment
Share on other sites

Thanks Alan for that...

 

I have another question that if we wish to use tlm_initiator_socket instead of simple_initiator_socket do we still require register callback....???

 

and when to use tlm_initiator_socket and simple_initiator_socket???....

 

With regards

Mohit Negi

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