チャネル
チャネルとは
SystemCは、モジュール間の信号通信に"チャネル"という概念を提供して接続する機構を持たせている。
チャネルとモジュール間は、インターフェースとポートを介して接続する。
チャネルはインターフェースを実装(継承)する。モジュール側がそのインターフェースを持ったポートによりチャネルにアクセスすることができる。
Verilogだとwireで信号を接続するが、チャネルはwireのように単純な接続から内部に調停するような機構を持たせた複雑なものも表現できる。
チャネルはSystemCライブラリにいくつか用意されているが、ユーザが各自設計することができる。
チャネルとモジュール間は、インターフェースとポートを介して接続する。
チャネルはインターフェースを実装(継承)する。モジュール側がそのインターフェースを持ったポートによりチャネルにアクセスすることができる。
Verilogだとwireで信号を接続するが、チャネルはwireのように単純な接続から内部に調停するような機構を持たせた複雑なものも表現できる。
チャネルはSystemCライブラリにいくつか用意されているが、ユーザが各自設計することができる。
チャネルには大きく分けて2種類ある。
- プリミティブチャネル(primitive channel)
- 階層チャネル(hierarchical channel)
プリミティブチャネルと階層チャネルの違いは、チャネル内にプロセスを持っているか持っていないかである。
プロセスを持っていないチャネルが、プリミティブチャネルで、
プロセスを持っているチャネルが、階層チャネルである。
プロセスを持っていないチャネルが、プリミティブチャネルで、
プロセスを持っているチャネルが、階層チャネルである。
プリミティブチャネル
sc_prim_channelについて
プリミティブチャネルはsc_prim_channelを継承している。
ユーザがプリミティブチャネルを作ることはまずない。
ユーザがプリミティブチャネルを作ることはまずない。
用意されているプリミティブチャネル一覧
sc_signal<type> | 信号(プロセス間、子モジュール間との通信用) |
sc_buffer<type> | sc_signalと同じ、値の書き込み時必ずイベント発生 |
sc_fifo<type> | FIFOバッファつき入出力チャネル(使い方) |
sc_signal_resolved | 1ビット幅の解決済み信号 |
sc_signal_rv<W> | ビット幅Wをもつ解決済み信号 |
sc_semaphore | 排他制御チャネル |
sc_mutex |
チャネルとポートの接続対応表
チャネルとポートの接続対応は次のとおり。
入力側 | チャネル | 出力側 |
sc_port<sc_signal_in_if<X> > | sc_signal<X> sc_buffer<X> |
sc_port<sc_signal_out_if<X> > |
sc_port<sc_signal_inout_if<X> > | sc_port<sc_signal_inout_if<X> > | |
sc_in<X> | sc_out<X> | |
sc_inout<X> | sc_inout<X> | |
sc_in<bool> | sc_clock | |
sc_in_resolved | sc_signal_resolved | sc_out_resolved |
sc_inout_resolved | sc_inout_resolved | |
sc_in_rv<W> | sc_signal_rv<W> | sc_out_rv<W> |
sc_inout_rv<W> | sc_inout_rv<W> | |
sc_port<sc_fifo_in_if<X> > | sc_fifo<X> | sc_port<sc_fifo_out_if<X> > |
sc_fifo_in<X> | sc_fifo_out<X> |
- X : 型(bool,unsigned char,int,sc_uint<>, sc_int<>, etc.)
- W : ビット幅(int型)
アクセス側 | チャネル |
sc_port<sc_mutex_if> | sc_mutex |
sc_port<sc_semaphore_if> | sc_semaphore |
sc_signalとsc_bufferの違いは?
sc_signalとsc_bufferの違いは、値が変化する/しないに関係なく書き込み時に毎回イベントが発生するか/しないかである。
値が変化したときのみイベントが発生するのは、sc_signal
値を書き込み時毎回イベントが発生するのは、sc_buffer
値が変化したときのみイベントが発生するのは、sc_signal
値を書き込み時毎回イベントが発生するのは、sc_buffer
- 例
sc_signal< int > sig_data;
sc_buffer< int > buf_data;
//初期値はどちらも"0"とする。
for (int i=0; i<10; i++) {
sig_data.write( 1 ); // sc_signalに10回"1"を書き込む
buf_data.write( 1 ); // sc_bufferに10回"1"を書き込む
}
////////////////////////////////////////
sc_in<int> sig_data;
sc_in<int> buf_data;
int cntr1;
int cntr2;
SC_CTOR( MOD )
: cntr1(0), cntr2(0) // カウンタの初期値を"0"にする
{
SC_METHOD( proc1 );
sensitive << sig_data; // sc_signal
SC_METHOD( proc2 );
sensitive << buf_data; // sc_buffer
}
void proc1() {
++cntr1;
printf( "cntr1 = %d\n", cntr1 ); // sc_signal
}
void proc2() {
++cntr2;
printf( "cntr2 = %d\n", cntr2 ); // sc_buffer
}
2つの信号(sig_data, buf_data)に毎回"1"を書き込んだとき、
sc_signalははじめの書き込み時の1回だけイベントが発生する。
sc_bufferは毎回の書き込み時、イベントが発生する。
したがって、cntr1の値は最後は"1"となり、cntr2の値は"10"となる。
sc_signalははじめの書き込み時の1回だけイベントが発生する。
sc_bufferは毎回の書き込み時、イベントが発生する。
したがって、cntr1の値は最後は"1"となり、cntr2の値は"10"となる。
sc_bufferはsc_signalを継承している。したがって、扱い方はほぼ同じといってよい。
ただし、2つのチャネルを併用したモデルは混乱するもとなので、片方のチャネルに統一して使ったほうがよい。
ただ、実際の設計では理想的にいかないかもしれないが。
ただし、2つのチャネルを併用したモデルは混乱するもとなので、片方のチャネルに統一して使ったほうがよい。
ただ、実際の設計では理想的にいかないかもしれないが。
sc_clockは何チャネル?
sc_clockはどうなのだろう?
sc_signal<bool>型を継承しているので、一応sc_prim_channelを継承していることになるのでプリミティブ?でも、クロックを供給しているから、やっぱり階層チャネルの分類になるんだろうか?
ポート、階層、SC_METHOD、SC_THREAD等はないので、やはりプリミティブとみてよいのかも。
sc_signal<bool>型を継承しているので、一応sc_prim_channelを継承していることになるのでプリミティブ?でも、クロックを供給しているから、やっぱり階層チャネルの分類になるんだろうか?
ポート、階層、SC_METHOD、SC_THREAD等はないので、やはりプリミティブとみてよいのかも。
階層チャネル
たとえば、バスプロトコルを設計するときに、複数のターゲッタを調停するためのアービタを設けたりする。そういったときに、チャネルにプロセスを持たせてアービタを実装する方法がある。
このとき、プロセスを持つチャネルのことを階層チャネルと呼ぶ。
階層チャネルはSystemCライブラリでは提供されていない?ので、ユーザが各自で設計することになる。
チャネルのクラスを定義するには sc_channel を継承する。
このとき、プロセスを持つチャネルのことを階層チャネルと呼ぶ。
階層チャネルはSystemCライブラリでは提供されていない?ので、ユーザが各自で設計することになる。
チャネルのクラスを定義するには sc_channel を継承する。
sc_channelについて
チャネルはsc_channelを継承する。
sc_channelはsc_module.hの544行目に以下のように記述されている。
sc_channelはsc_module.hの544行目に以下のように記述されている。
typedef sc_module sc_channel;
つまり、「sc_module = sc_channel」であるためチャネルはモジュールと同じ扱いができる。
違いは、モジュールは自らが動作する。
それに対してチャネルはモジュールからのアクセスを受けることで動作する。
チャンネルはインタフェースを実装する。
違いは、モジュールは自らが動作する。
それに対してチャネルはモジュールからのアクセスを受けることで動作する。
チャンネルはインタフェースを実装する。
まとめ
チャネルを理解するためには次の内容が区別できているかが重要になる。
- チャネル
- インターフェース
- ポート
ここでは、インタフェースとポートにはほとんど触れなかったが。。。