TLM-2.0 b_transportについて
b_transportについて
void b_transport( tlm_generic_payload& , sc_time& )
b_transportはイニシエータからターゲットにデータ転送するときに使用するI/Fの関数。
b_transportはtlm_blocking_transport_ifの純粋仮想関数。
tlm_fw_transport_ifはこのtlm_blocking_transport_ifを継承しているので、tlm_fw_transport_ifを使ってインターフェースを準備するにはb_transportの定義が必要となる。
ブロッキングなので、b_transportではwait記述が可能。もちろんなくてもかまわない。
第1引数tlm_generic_payloadは共通のトランザクション。
第2引数sc_time& はタイミングアノテーション用。
LTモデルでは、sc_timeはSC_ZERO_TIMEを渡す。
b_transportはtlm_blocking_transport_ifの純粋仮想関数。
tlm_fw_transport_ifはこのtlm_blocking_transport_ifを継承しているので、tlm_fw_transport_ifを使ってインターフェースを準備するにはb_transportの定義が必要となる。
ブロッキングなので、b_transportではwait記述が可能。もちろんなくてもかまわない。
第1引数tlm_generic_payloadは共通のトランザクション。
第2引数sc_time& はタイミングアノテーション用。
LTモデルでは、sc_timeはSC_ZERO_TIMEを渡す。
LTモデルのb_transportの簡単な記述例(時間無し)
ターゲット側で、レジスタを用意して、アドレス指定してRead/Writeアクセス。
イニシエータ側はアドレスを指定してデータを書き込み、そのあと同じアドレスに対してデータを読み込む。
イニシエータ側はアドレスを指定してデータを書き込み、そのあと同じアドレスに対してデータを読み込む。
基本的なアクセスは以下のような感じになる。
- イニシエータ側でb_transportを呼ぶ
- ターゲット側に実装されたb_transportが処理される
- ターゲット側は最後にresponse_statusを設定してイニシエータに戻す(return)
- イニシエータはresponse_statusをみて正しく処理されたか確認する
ターゲット側
// メンバ変数
enum { REG_MAX_SIZE=256 }; // レジスタのサイズ
unsigned int Reg[REG_MAX_SIZE]; // レジスタを用意
void b_transport( tlm::tlm_generic_payload &trans, sc_time &time )
{
// アドレス取得
unsigned int address = static_cast<unsigned int>(trans.get_address());
// データポインタ
unsigned int *data_ptr = reinterpret_cast<unsigned int*>(trans.get_data_ptr());
// unsigned int data_length = trans.get_data_length();
// unsigned int streaming_width = get_streaming_width();
// unsigned char* byte_enable_ptr = get_byte_enable_ptr();
// unsigned int byte_enable_length = get_byte_enable_length();
// bool dmi = is_dmi_allowed();
unsigned int idx = address/4;
if (idx < REG_MAX_SIZE) {
if (trans.is_read()) { // TLM_READ_COMMAND
// Read動作
*data_ptr = Reg[idx];
//wait( 10, SC_US );
trans.set_response_status( tlm::TLM_OK_RESPONSE ); // アクセスOK
}
else if (trans.is_write()) { // TLM_WRITE_COMMAND
// Write動作
Reg[idx] = *data_ptr;
//wait( 15, SC_US );
trans.set_response_status( tlm::TLM_OK_RESPONSE ); // アクセスOK
}
else { // TLM_IGNORE_COMMAND
trans.set_response_status( tlm::TLM_COMMAND_ERROR_RESPONSE ); // アクセスERROR
}
}
else {
cout << " Address Error: " << "addr=" << hex << address
<< " (MAX_SIZE=" << REG_MAX_SIZE << ")" << endl;
trans.set_response_status( tlm::TLM_ADDRESS_ERROR_RESPONSE ); // アドレス指定エラー
}
}
イニシエータ側
void thread0()
{
unsigned int addr = 0x100;
{ // 書き込み動作
unsigned int data = 0x1234; // 適当な値
tlm::tlm_generic_payload* trans = new tlm::tlm_generic_payload;
sc_time time = SC_ZERO_TIME;
// データ書き込み設定
trans->set_address( addr );
trans->set_data_ptr( reinterpret_cast<unsigned char*>(&data) );
trans->set_data_length( 4 ); // byte
trans->set_write(); // set_command( tlm::TLM_WRITE_COMMAND );
i_socket->b_transport( *trans, time );
if (trans->is_response_ok()) {
cout << "Initiator::Write Access OK" << endl;
cout << " Write Data=0x" << hex << data << endl;
}
else if (trans->is_response_error()) {
cout << "Initiator::Write Access ERROR" << endl;
}
delete trans;
}
{ // 読み込み動作
unsigned int data;
tlm::tlm_generic_payload* trans = new tlm::tlm_generic_payload;
sc_time time = SC_ZERO_TIME;
// データ読み込み設定
trans->set_address( addr );
trans->set_data_ptr( reinterpret_cast<unsigned char*>(&data) );
trans->set_data_length( 4 ); // byte
trans->set_read(); // set_command( tlm::TLM_READ_COMMAND );
i_socket->b_transport( *trans, time );
if (trans->is_response_ok()) {
cout << "Initiator::Read Access OK" << endl;
cout << " Read Data=0x" << hex << data << endl;
}
else if (trans->is_response_error()) {
cout << "Initiator::Read Access ERROR" << endl;
}
delete trans;
}
}
注意点
ここでの記述例は、イニシエータではthreadの関数から直接ソケットのb_transport()関数を呼んだり、ターゲットではb_transport関数内で直接処理を記述したりしている。
今回は説明のために直接記述しているが、本来これは、よくない記述。
コーディングルールにのっとるなら、通信部分と機能記述を分離しなければならない。
分離には継承とvirtual =0を駆使するとできる。
今回は説明のために直接記述しているが、本来これは、よくない記述。
コーディングルールにのっとるなら、通信部分と機能記述を分離しなければならない。
分離には継承とvirtual =0を駆使するとできる。