sc_fifoチャネル
間違いがあったらゴメンサイ。
sc_fifoはプリミティブチャネルの1つ。
(プリミティブチャネルはプロセスを持たないチャネルのこと、対比して階層チャネルがある。)
TLMレベルのモデルでよく使われる。
設計仕様が要求されないテストベンチ等では(扱いが簡単なので)よく使っている。
(プリミティブチャネルはプロセスを持たないチャネルのこと、対比して階層チャネルがある。)
TLMレベルのモデルでよく使われる。
設計仕様が要求されないテストベンチ等では(扱いが簡単なので)よく使っている。
入力ポート:sc_fifo_in<>
sc_fifo_inはsc_fifoの入力ポートとして作成するためのもの。
sc_fifo_in : sc_port<sc_fifo_in_if<T>,0>を継承。
メソッドを呼び出すプロセスはSC_THREADもしくはSC_CTHREAD。
sc_fifo_in : sc_port<sc_fifo_in_if<T>,0>を継承。
メソッドを呼び出すプロセスはSC_THREADもしくはSC_CTHREAD。
- 宣言例
SC_MODULE( MOD ) {
sc_fifo_in< sc_uint<32> > fifo_data;
SC_CTOR( MOD )
: fifo_data( "fifo_data" )
{
}
};
read ()
fifoチャネルからブロッキング読み出しを行い、その値を返す。
もし、チャネルにデータが空のときは待つ(ブロッキングする/waitする)。
もし、チャネルにデータが空のときは待つ(ブロッキングする/waitする)。
- 使用例
void thread_proc() {
while(true) {
tmp = fifo_data.read(); // データが空のときここでwaitする
// fifo_dataにデータが来ることで動作開始
・・・
}
}
read()はブロッキング読み込みのため、fifo_dataにデータが来なかったとき、このプロセスは停止したままの状態になってしまう。
もし、あなたがデータが来ない間も、停止させないでこのプロセスで別の仕事をさせたいことがあるときはnb_read()を使用するとよい。
もし、あなたがデータが来ない間も、停止させないでこのプロセスで別の仕事をさせたいことがあるときはnb_read()を使用するとよい。
nb_read(変数)
fifoチャネルからノンブロッキング読み出しを行い、その値を返す。
もし、チャネルにデータが空でもブロッキングせず、戻り値としてfalse(読み出し失敗)を返す。
num_available()と組み合わせて使うとよい。
もし、チャネルにデータが空でもブロッキングせず、戻り値としてfalse(読み出し失敗)を返す。
num_available()と組み合わせて使うとよい。
num_available()
fifoチャネル内で利用可能なデータ数をint型で返す。
もし、fifoが空のときは0を返し、データがあるときはその数を返す。
もし、fifoが空のときは0を返し、データがあるときはその数を返す。
- 使用例
void thread_proc() {
while(true) {
if (fifo_data.num_available() > 0) { // データが空でないとき
fifo_data.nb_read( tmp ); // 値を取得
}
else {
// データが空のときの処理
}
}
}
data_written_event()
書き込みアクセスが発生したときに起こるイベントとしてsc_eventを返す。
- 使用例
void thread_proc() {
while(true) {
wait( fifo_data.data_written_event() ); // データ書き込みを待つ
while (in_data.num_available() > 0) {
fifo_data.nb_read( tmp );
・・・
}
}
}
出力ポート:sc_fifo_out<>
sc_fifo_outはsc_fifoの出力ポートとして作成するためのもの。
sc_fifo_out : sc_port<sc_fifo_out_if<T>,0>を継承。
メソッドを呼び出すプロセスはSC_THREADもしくはSC_CTHREAD。
sc_fifo_out : sc_port<sc_fifo_out_if<T>,0>を継承。
メソッドを呼び出すプロセスはSC_THREADもしくはSC_CTHREAD。
- 宣言例
SC_MODULE( TB ) {
sc_fifo_out< sc_uint<32> > fifo_data;
SC_CTOR( TB )
: fifo_data( "fifo_data" )
{
}
};
write(値)
引数の値をブロッキング書き込みでfifoにデータを渡す。
fifo内のデータ(領域)がいっぱいで空でないとき待機する(ブロッキングする/waitする)。
fifo内のデータ(領域)がいっぱいで空でないとき待機する(ブロッキングする/waitする)。
- 使用例
void thread_proc() {
while(true) {
・・・
fifo_data.write(tmp); // fifoがいっぱいのときここでwaitする
}
}
write()はブロッキング読み込みのため、fifo_dataがいっぱいだったとき、このプロセスは停止したままの状態になってしまう。
もし、あなたがfifo_dataがいっぱいになってしまっても、停止させないでこのプロセスで別の仕事をさせたいことがあるときはnb_read()を使用するとよい。
もし、あなたがfifo_dataがいっぱいになってしまっても、停止させないでこのプロセスで別の仕事をさせたいことがあるときはnb_read()を使用するとよい。
nb_write(値)
引数の値をノンブロッキング書き込みでfifoにデータを渡す。
fifo内のデータ(領域)がいっぱいで空でないとき、戻り値としてfalse(書き込み失敗)を返す。
num_free()と組み合わせて使うとよい。
fifo内のデータ(領域)がいっぱいで空でないとき、戻り値としてfalse(書き込み失敗)を返す。
num_free()と組み合わせて使うとよい。
num_free()
fifo内で利用可能な開き領域の数をint型で返す。
もし、fifo内がいっぱいのときは戻り値として0を返す。
もし、fifo内がいっぱいのときは戻り値として0を返す。
- 使用例
void thread_proc() {
while(true) {
・・・
if (fifo_data.num_free() > 0) { // データが空でないとき
fifo_data.nb_write( tmp ); // 値を書き込む
}
else {
// データがいっぱいのときの処理
}
}
}
data_read_event()
読み出しアクセスが発生したときに発生するイベントsc_eventを返す。
- 使用例
void thread_proc() {
while(true) {
wait( fifo_data.data_read_event() ); // データ読み込みを待つ
while (fifo_data.num_free() > 5) {
・・・
fifo_data.nb_write( tmp ); // fifoの空が5より多いとき一気に書き込む
}
}
}
信号の接続
sc_fifo_in<>とsc_fifo_out<>を接続するにはsc_fifo<>チャネルを使用する。
- 接続例
SC_MODULE( TOP ) {
sc_fifo< sc_uint<32> > fifo_data; //チャネル宣言
MOD *mod;
TB *tb;
SC_CTOR( MOD )
: fifo_data( "fifo_data", 32 ) // 第2引数でfifoの領域サイズを設定
{
mod = new mod( "mod" );
mod->fifo_data( fifo_data ); // bind
tb = new mod( "tb" );
tb->fifo_data( fifo_data ); // bind
}
};
コンストラクタの初期化リストでfifoの領域サイズを指定した。
指定しない(デフォルト)の場合、サイズは16が設定される。(無限サイズではないことに注意)
指定しない(デフォルト)の場合、サイズは16が設定される。(無限サイズではないことに注意)
ブロッキング/ノンブロッキングについて
ブロッキングは、その関数内にwaitが存在することを意味する。
そのため使用者は、ブロッキングであることを承知した上で設計しなければならない。
逆にノンブロッキングは、その関数内にwaitが存在しないことを意味する。
そのため使用者は、ブロッキングであることを承知した上で設計しなければならない。
逆にノンブロッキングは、その関数内にwaitが存在しないことを意味する。
ブロッキングの関数は、関数名の先頭に明示的に"b_"が付いたり、もしくは何も付かない。
ノンブロッキングの関数は、関数名の先頭に明示的に"nb_"が付く。
2種類のメソッドが用意されている場合には何かしら区別がつけられるように工夫されている。
もし、自分でインターフェースを設計する場合には、明示的に"b_"、"nb_"を付けるとよい。
ノンブロッキングの関数は、関数名の先頭に明示的に"nb_"が付く。
2種類のメソッドが用意されている場合には何かしら区別がつけられるように工夫されている。
もし、自分でインターフェースを設計する場合には、明示的に"b_"、"nb_"を付けるとよい。
BCAで扱うには
たとえば、SC_CTHREADでクロックサイクルで動作するような(バス)モデルで扱うような場合にwait()を使用する。
そのときは、ブロッキングではなくノンブロッキングを使用したほうがよい。
(ブロッキングだとwait(event)を使用することになるので不都合があるかもしれない)
簡単なのはdo-while文を使用する方法。
そのときは、ブロッキングではなくノンブロッキングを使用したほうがよい。
(ブロッキングだとwait(event)を使用することになるので不都合があるかもしれない)
簡単なのはdo-while文を使用する方法。
読み込み側
- データが来るまで待つ動作
SC_CTHREAD( cthread_proc, clk.pos() );
void cthread_proc() {
while(true) {
do { wait(); } while (fifo_data.num_available() > 0); // fifoにデータが来るまで待つ
fifo_data.nb_read( tmp ); // 値を読み込む
・・・
}
}
書き込み側
- データがいっぱいであるとき待つ動作
SC_CTHREAD( cthread_proc, clk.pos() );
void cthread_proc() {
while(true) {
・・・
do { wait(); } while (fifo_data.num_free() > 0); // fifo領域が空くまで待つ
fifo_data.nb_write( tmp ); // 値を書き込む
}
}
添付ファイル