Ejemplo de Untimed3 min read

Vamos con el primer ejemplo…

Initiator

Empezamos con los includes de las cabeceras necesarias

#include 

using namespace sc_core;

#include "tlm.h"

#include "tlm_utils/simple_initiator_socket.h"

Primero incluimos systemc (previsible, eh?) y luego tlm.h (también previsible).

Por último incluimos el socket mas sencillo de todos para este ejemplo.

A continuación declaramos la classe Initiator

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();

};

Aquí hay cosas más interesantes: primero definimos la clase Initiator como un hijo de sc_module. A continuación definimos un socket de tipo simple_initiator, le llamamos initiator_socket (soy muy original para los nombres). A este template (los usaremos a menudo), se le pasa como parámetro la propia clase que lo contiene.

Luego declaramos el constructor usando la macro SC_HAS_PROCESS().

Por último definimos un método que será un SC_THREAD llamado initiator_thread (original, eh?).

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

sc_time delay = SC_ZERO_TIME;
...

Dentro del SC_THREAD declaramos una variable transaction y una variable sc_time para anotar los tiempos (serán 0, pero hace falta declararlos). También la variable double data que seran los datos a enviar entre los módulos.

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) );

Llenamos los campos de la transacción, creo que cada campo se explica por si solo, y sólo vale la pena comentar las últimas lineas. Declaramos la transacción como TLM_INCOMPLETE_RESPONSE (así lo marca el estandard).

Luego preparamos los datos, para eso actualizamos el apuntador de la transacción a nuestros datos y lo hacemos con un «cast» en versión C++ (puedes consultar este link donde lo explica bastante bien). Fíjate que la transacción sólo mueve el puntero a los datos, no los datos en sí.

transaction.set_command( tlm::TLM_WRITE_COMMAND );

transaction.set_address( i );

initiator_socket-&>b_transport( transaction, delay);

En estas tres linias se pone el comando de la transacción que sea una escritura, la dirección donde acceder, y se realiza (por fin!) la comunicación con la función b_transport. A esta función se le pasa la transacción (transaction) y el tiempo de esta transacción (en este modo sera 0).

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

A continuación deberíamos comprobar si el Target ha respondido con un TLM_OK_RESPONSE a la transacción.

Acto seguido hacemos lo mismo pero para el caso de lectura (cambiando el comando por TLM_READ_COMMAND, claro).

Target

Vamos ahora a por el código del Target

#include "tlm_utils/simple_target_socket.h"

...

tlm_utils::simple_target_socket target_socket;

A diferencia del Target, aquí incluimos este header para incluir el socket para el target y declaramos una variable con el socket mismo (pasándole como parámetro la clase que lo contiene).

Veamos ahora el código del constructor:

Target::Target(sc_module_name name_):

sc_module(name_),

target_socket("target_socket")

{

target_socket.register_b_transport(this, &Target::b_transport);

}

Nada extraño hasta la última línea, donde registramos la función que implementa la función b_transport (puede tener cualquier nombre).

Y a continuación la función en sí:

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;

}

Primero recogemos todos los distintos parámetros de la transacción, y luego según la transacción sea de escritura o lectura, hacemos la copia de datos pertinente.

Fíjate de nuevo que la transacción sólo contiene un puntero, y hay que acceder a los datos del puntero con un "cast".

Por último, ponemos el estatus de la transacción como un OK (TLM_OK_RESPONSE) y volvemos de la función.

Y hasta aquí todo el código necesario para un modelado Untimed. Sencillo verdad?

Puedes bajarte todo el código en este enlace

This entry was posted in Ejemplos and tagged , , , , , . Bookmark the permalink. Follow any comments here with the RSS feed for this post. Both comments and trackbacks are currently closed.

1 Trackback

  1. By Ejemplo de Loosely-timed | Màrius on TLM on jueves, 26 marzo 2009 at %H:%M 08Thu, 26 Mar 2009 20:15:02 +000002.

    […] pues el ejemplo del modo untimed, que con eso casi casi lo tenemos ya […]