4. 2 簡単な例題
ここでは、簡単な例題をとおしてSystemCの使い方を学びます。
ここでは、簡単な例題をとおしてSystemCの使い方を学びます。
ここでは、単純化された cpu モデルを SystemC で記述します。 この cpu をここでは cpu0 と呼びます。 この cpu0には、次の 2 つの機能を持たせます。
SystemCではC++をベースにしているため、 オブジェクト指向の考え方でシステムをとらえることにします。 オブジェクト指向のソフトウェア設計で、システムの要求分析と設計に UML(Unified Modeling Language) が注目されています。
まず、上記の問題設定から、 システムのもつべき機能をユースケース図で表わします。

ここではシステムが、 楕円のなかに記述されている機能を持つことを表わしています。
システムの動的な連携を表現するにはシーケンス図を用います。

ここでは
ことを表わしています。
ここで cpu0 と外部との信号のやりとりを整理します。
このブロック図は以下のようになります。

ここでモジュール cpu0 の定義をする準備ができたので、 さっそく SystemC で定義してみましょう。
まずモジュールの cpu0 のモジュールクラスとコンストラクタを定義します。 コンストラクタとは、C++ でオブジェクトを初期化生成する関数のことです。 モジュールの定義の方法については詳しくは後述しますが、 例えば次のような形になります。
#include <systemc.h>
SC_MODULE(cpu) // cpu というモジュールクラスを定義する
{
public: // 公開部分
sc_in<bool> reset;
sc_in<bool> clk;
sc_out<int> cpu_out;
enum {maxmem =100}; // 公開する内部変数
int memdata[maxmem];
int pc;
void main(); // 公開するメンバ関数
void cpureset();
SC_CTOR(cpu) { // コンストラクタ (初期化部分)
SC_METHOD(cpureset);
sensitive << reset.neg();
SC_METHOD(main);
sensitive << clk.pos();
}
};
初期化関数cpureset()の定義は以下のようになります。 ここでは、memdata[i]に i を書き込むという単純な動作として定義することにします。
void
cpu::cpureset(){
cout << "simulation initialization \n";
for (int i=0; i<maxmem; i++){
memdata[i]=i;
pc = 0;
}
}
メモリ読み出し関数は以下のようになります。
void
cpu::main()
{
cpu_out = memdata[pc];
cout << "pc = " << pc <<" memdata[pc]=" << memdata[pc] <<endl;
pc = pc + 1;
if (pc == maxmem-1)
sc_stop();
}
SystemCにおいては、ユーザが定義するメイン関数は sc_main()関数です。
ここでは、
という内容を記述しています。
int sc_main (int argc , char *argv[]) {
sc_signal<bool> reset;
sc_signal<int> cpu_out;
sc_clock clk("clk", 10, 0.5 , 100, 0);
cpu cpu1("cpu1");
cpu1.reset(reset);
cpu1.clk(clk);
cpu1.cpu_out(cpu_out);
sc_start(10 );
reset = 1;
sc_start(20 );
reset = 0;
sc_start(1000 );
sc_stop();
return 0;
}
シミュレーションを実行するとつぎの結果を得ます。
(run result)
simulation initialization
pc = 1 memdata[pc]=1
simulation initialization
pc = 1 memdata[pc]=1
pc = 2 memdata[pc]=2
pc = 3 memdata[pc]=3
pc = 4 memdata[pc]=4
pc = 5 memdata[pc]=5
pc = 6 memdata[pc]=6
pc = 7 memdata[pc]=7
pc = 8 memdata[pc]=8
pc = 9 memdata[pc]=9
つぎの A1?A4のうち正しいのはどれでしょうか?
| A1 | cpureset()が実行されてからmain()が実行され正常終了する |
| A2 | main()が先に実行され初期化ができていないため、異常終了する |
| A3 | 正常に終了するか、異常終了するかシステムに依存するがいつもどちらか一方に決まる |
| A4 | 正常終了するか、異常終了するか決まらない |
正解は A3、およびA4です。
このような状態を非決定性(Non Deterministic)と呼びます。 システムを設計するうえで、 最終的なシステムの振舞いが非決定的にならないよう注意する必要があります。
SystemCのシミュレータは、 時としてこのようにシステムの最終的な振舞いが非決定的な振舞いになってしまう場合があります。
これを避けるためには
などの方法が考えられます。
では、答えがなぜA3、A4と、二つあるのでしょうか? これは、 振舞いに非決定的な部分があるかどうか調べるため、 SystemCのシミュレータには、 同時刻に起動されるプロセスの実行順序を意図的にランダムにするという機能があります。 このため、 通常はA3ですが、A4も可能になります。
答えは"No"です。 これはこれら2つのプロセスは SC_METHOD として定義されているからです。 並行して走るプロセスとして定義するには SC_THREAD を用いてプロセスを登録します。