Untimed example

Let’s start with the first example…

Initiator

We shall start with the include’s

#include 

using namespace sc_core;

#include "tlm.h"
#include "tlm_utils/simple_initiator_socket.h"

Firstly we include systemc and then tlm.h
Then we include the easiest socket for that example.
Now it’s time to declare the Initiator class

class Initiator: sc_module
{
public:
  tlm_utils::simple_initiator_socket initiator_socket;
  SC_HAS_PROCESS(Initiator);
  Initiator(sc_module_name name_);

private:
  void initiator_thread();
};


Lot of interesting things there: Firstly we define the Initiator class as dereived from sc_module. Following we declare a simple_initiator socket, we name it initiator_socket (very original…). To this template (we use a lot of them), we pass as parameter the class that contains it.

Later we declare the constructor with the macro SC_HAS_PROCESS().
Finally we declare a method to be SC_THREAD called initiator_thread (another original name).

...
double data;
tlm::tlm_generic_payload transaction;

sc_time delay = SC_ZERO_TIME;
...

In the SC_THREAD we declare a transaction variable and a sc_time variable to annotate times (it will be 0, but we must declare it). We also declare the variable data of type double that it will be data to send between modules.

transaction.set_data_length( sizeof(data) );
transaction.set_streaming_width( sizeof(data) );
transaction.set_byte_enable_ptr(0);
transaction.set_dmi_allowed(false);
transaction.set_response_status( tlm::TLM_INCOMPLETE_RESPONSE );
transaction.set_data_ptr( reinterpret_cast(&data) );

We fill the transaction fields, names are self-explanatory. I comment last lines.
We declare the transaction as TLM_INCOMPLETE_RESPONSE (standard says that).
Then we prepare data, for that, we put the transaction pointer to point to our data and do a C++ cast.
Note that the transaction only moves the pointer to data, not the data.

transaction.set_command( tlm::TLM_WRITE_COMMAND );
transaction.set_address( i );
initiator_socket-&>b_transport( transaction, delay);

These three lines fill the transaction fields to be a write, the address to write to, and the transaction is done using b_transport function call. To that function we pass the transaction and the time for that transaction (will be 0 for this example).

if (transaction.get_response_status() == tlm::TLM_OK_RESPONSE)

Next we check if Target answers with a TLM_OK_RESPONSE saying that transaction is done.
Example follows performing reads instead of writes (changing TLM_READ in the proper field, of course).

Target

Let’s see the Target code:

#include "tlm_utils/simple_target_socket.h"
...
tlm_utils::simple_target_socket target_socket;

We include the header for the Target socket and we declare a variable with the socket (with the class itself as template parameter).

Constructor code:

Target::Target(sc_module_name name_):
  sc_module(name_),
  target_socket("target_socket")
{
  target_socket.register_b_transport(this, &Target::b_transport);
}

All seems normal, but the last line is a little tricky: here we register what function implements the method b_transport

Following, the function:

void Target::b_transport( tlm::tlm_generic_payload& transaction, sc_time& delay )
{
  tlm::tlm_command command = transaction.get_command();
  sc_dt::uint64    address = transaction.get_address();
  unsigned char*   data_ptr = transaction.get_data_ptr();
  unsigned int     length = transaction.get_data_length();
  unsigned char*   byte_enable_ptr = transaction.get_byte_enable_ptr();
  unsigned int     width = transaction.get_streaming_width();
  double *my_data_ptr;
  if (command == tlm::TLM_WRITE_COMMAND) {
    data[address] = *(reinterpret_cast( data_ptr ) );
    std::cout << "Target Write: " << sc_time_stamp() << ". Data: " << data[address] << std::endl;
  } else {
    my_data_ptr = reinterpret_cast(data_ptr);
    *my_data_ptr = data[address];
    std::cout << "Target Read: " << sc_time_stamp() << ". Data " << data[address] << std::endl;
  }

  transaction.set_response_status(tlm::TLM_OK_RESPONSE );
  return;
}

First we collect all transaction parameters, and then if the transaction is read or write, we do the right copy between data.
Look again: transaction only contains the pointer to data, no the data, so we need to access to data using that pointer casted.
Finally, we put the status of the transaction to an OK (TLM_OK_RESPONSE) and return from the function.

Here ends the untimed example, easy! 😛

Download full code example from en este enlace

One thought on “Untimed example”

Leave a Reply