SystemCでユーザデータタイプを使う
sc_signal<>やsc_buffer<>を介したデータやりとりは、既に定義されたbool,int,sc_int<>等は問題なく使うことができます。
しかし、ユーザが独自に構造体を定義して、それを受渡しする場合問題が生じる。
ここでは、sc_signal<>もしくはsc_buffer<>でユーザデータタイプを使用する方法をメモします。
しかし、ユーザが独自に構造体を定義して、それを受渡しする場合問題が生じる。
ここでは、sc_signal<>もしくはsc_buffer<>でユーザデータタイプを使用する方法をメモします。
ユーザデータタイプを使うときの問題
次のコードを見てください。
struct StrData {
bool valid;
int data;
};
int sc_main( int, char** ) {
sc_signal<StrData> sig;
}
上記をコンパイルしようとすると、次のようなエラーが発生します。
/usr/local/systemc-2.2.0/include/sysc/communication/sc_signal.h: In member function ‘void sc_core::sc_signal<IF>::write(const T&) [with T = StrData]’:
main.cpp:119: instantiated from here
/usr/local/systemc-2.2.0/include/sysc/communication/sc_signal.h:221: error: no match for ‘operator==’ in ‘((sc_core::sc_signal<StrData>*)this)->sc_core::sc_signal<StrData>::m_new_val == ((sc_core::sc_signal<StrData>*)this)->sc_core::sc_signal<StrData>::m_cur_val’
・・・
・・・
はじめなんじゃこりゃってなりますが、‘operator==’がどうやら足りないというメッセージのようです。
なにか工夫をしないといけないようです。
なにか工夫をしないといけないようです。
ユーザデータタイプを使うための解決
ユーザデータタイプをsc_signal<>やsc_buffer<>で使う場合は、次の3つを定義してあげます。
- bool operator==()
- sc_trace()
- ostream& operator<<()
具体的には、次のように修正します。
struct StrData {
bool valid;
int data;
// sc_signal<>で使う
bool operator==(const StrData& other) const {
return ( (valid == other.valid)
&& (data == other.data) );
}
};
// トレース時使用する
void sc_trace( sc_trace_file*& tf, const StrData& trans, std::string name )
{
sc_trace( tf, trans.valid, name + ".valid" );
sc_trace( tf, trans.data, name + ".data" );
}
// SystemCで使う
ostream& operator<<( ostream& os, const StrData& trans )
{
os << "(" << trans.valid << ", " << trans.data << ")";
return os;
}
int sc_main( int, char** ) {
sc_signal<StrData> sig;
}
構造体1つを扱うのにこれだけ定義が増えるのはちょっと面倒臭いですが、これもSystemCの仕様なのでしかたないです。
ここで、operator==はちゃんと書かないとダメですが、sc_trace()とoperator<<()の関数の中身は、ないと不便なだけで書かなくてもコンパイルできます。
面倒臭いときは、わたしは省略しちゃいます。
面倒臭いときは、わたしは省略しちゃいます。
bool operator==()はなぜ必要?
次のコードを見てください。
SC_MODULE(MOD)
{
sc_in<StrData> din;
SC_CTOR(MOD) {
SC_METHOD( method );
sensitive << din; // dinが変化したとき
}
void method() {
std::cout << "din = " << din.read() << std::endl;
}
};
メソッドであるmethod()がよばれるのは、sensitive<<dinよりdinが変化したときであるとわかります。
「変化した」というのをSystemCではどうやって判断しているかというと内部で"=="で比較しています。なので"=="で比較できるというのが前提でSystemCが設計されているので、ないとコンパイル時に"operator==が無い"と怒られるわけです。
SystemCデータタイプであるsc_int<>やsc_fixed<>はちゃんとoperator==が定義されているので、そんなことは気にしなくても使えます。
「変化した」というのをSystemCではどうやって判断しているかというと内部で"=="で比較しています。なので"=="で比較できるというのが前提でSystemCが設計されているので、ないとコンパイル時に"operator==が無い"と怒られるわけです。
SystemCデータタイプであるsc_int<>やsc_fixed<>はちゃんとoperator==が定義されているので、そんなことは気にしなくても使えます。
テンプレートを使用したユーザデータタイプの場合
次のようなテンプレートを使ったデータタイプを見てみます。
template <typename DT, int N>
struct Payload {
bool w_flag;
int address;
DT data[N];
};
次のように修正します。
template <typename DT, int N>
struct Payload {
bool w_flag;
int address;
DT data[N];
// sc_signal<> で必要
template<typename ODT,int ON>
bool operator==( const Payload<ODT,ON>& other) const {
bool ret;
ret = (w_flag == other.w_flag)
&& (address == other.address);
for (int i=0; i<N; i++)
ret = ret && (data[i] == other.data[i]);
return ret;
}
};
// トレースで必要
template <typename DT, int N>
void sc_trace( sc_trace_file*& tf, const Payload<DT,N>& trans, std::string name )
{
sc_trace( tf, trans.w_flag, name + ".w_flag" );
sc_trace( tf, trans.address, name + ".address" );
for (int i=0; i<N; i++) {
std::ostringstream oss;
oss << name << ".data_" << i;
sc_trace( tf, trans.address, oss.str() );
}
}
// SystemCで必要
template <typename DT, int N>
ostream& operator<<( ostream& os, const Payload<DT,N>& trans )
{
os << "("
<< trans.w_flag << ", "
<< trans.address << ", ";
for (int i=0; i<N; i++)
os << (int)trans.data[i] << ", ";
os << ")";
return os;
}