(57)【要約】【課題】コンテキスト切り替え制御のオーバーヘッドを減少させて処理時間を短縮することが可能な、SystemCシミュレータをベースとしたハード・ソフト協調検証用シミュレータを提供する。【解決手段】ハードウエアとソフトウエアのシミュレーション・モデルとして生成された複数のスレッドに対応して、そのシミュレーション時刻を制御するためのタイムキーパーを設ける。各タイムキーパー１２は、スレッド毎のシミュレーション時刻Tsimを保持する変数Ｘ、積算時間Tsumを保持する変数Ｙ、及び中断時刻と対応する中断メソッドを格納する中断要求待ち行列Ｑを有し、スレッドから６種類のメソッド呼び出しに応じて変数ｘ，ｙと待ち行列Ｑを管理し、必要な場合にSystemCシミュレータ１１のwait関数を呼び出す。これにより、wait関数呼び出し回数が削減され、全体の処理時間が短縮できる。【選択図】図１
2008059192.tif 000002
【特許請求の範囲】
【請求項１】
ハードウエアとソフトウエアの協調検証を行うためのＣ言語ベースのハード・ソフト協調検証用シミュレータであって、
前記ハードウエア及びソフトウエアに対応するシミュレーション・モデルを構成する複数のスレッド毎に設けられ、それぞれが対応するスレッドのシミュレーション時刻を制御するために、シミュレーション時刻を保持する第１の変数、積算時間を保持する第２の変数、中断時刻と対応する中断メソッドを格納する中断要求待ち行列、及び処理用の関数を備えた複数のタイムキーパーと、
前記タイムキーパーからの要求に応じて、管理しているシステム時刻を与えられた要求時間だけ進めると共に、並行して動作している前記スレッド間のコンテキスト切り替えを制御するＣ言語ベースのシミュレータ本体とを、
備えたことを特徴とするハード・ソフト協調検証用シミュレータ。
【請求項２】
前記各タイムキーパーは、それぞれ、
呼び出しに応じて前記第１の変数のシミュレーション時刻を返す第１の関数と、
呼び出しに応じて前記シミュレーション時刻から前記積算時間を指しい引いた値を前記システム時刻として返す第２の関数と、
呼び出しに応じて前記第２の変数の積算時間を前記要求時間として前記シミュレータ本体のシステム時刻を進めた後、該第２の変数をゼロクリアする第３の関数と、
与えられた中断時刻、中断システム時刻及び中断メソッドを前記中断要求待ち行列に登録する第４の関数と、
前記中断要求待ち行列が空の場合には、前記シミュレーション時刻に引数として与えられる経過時間を加算して該シミュレーション時刻を進めると共に前記積算時間に該経過時間を加算して該積算時間を更新し、前記中断要求待ち行列が存在しかつ前記シミュレーション時刻が中断時刻未満の場合には、該シミュレーション時刻に前記経過時間を加算してそのシミュレーション時刻を進め、前記中断要求待ち行列が存在しかつ前記シミュレーション時刻が中断時刻以上の場合には、該中断要求待ち行列の内で中断時刻がシミュレーション時刻以上である中断メソッドを呼び出す第５の関数と、
引数として与えられた時刻が現在の前記シミュレーション時刻よりも大きいときに、該時刻と更新後のシミュレーション時刻の差分を引数とし前記第５の関数を呼び出す第６の関数とを、
備えたことを特徴とする請求項１記載のハード・ソフト協調検証用シミュレータ。
【請求項３】
前記第５の関数は、前記中断要求待ち行列が存在しかつ更新したシミュレーション時刻が該中断要求待ち行列の先頭に格納された中断時刻に達したときに、該中断待ち行列の先頭から順に中断メソッドを呼び出し、その後シミュレーション時刻に前記積算時間を加算してこのシミュレーション時刻を進めると共に、該積算時間に前記経過時間を加算して該積算時間を更新し、この更新した積算時間が所定の閾値を越えた場合に前記第３の関数を呼び出すように構成したことを特徴とする請求項２記載のハード・ソフト協調検証用シミュレータ。
【請求項４】
タイムキーパー識別子で指定されるタイムキーパーに対して前記第４の関数を呼び出す第７の関数と、
前記タイムキーパー識別子で指定されるタイムキーパーに対して前記第３の関数を呼び出す第８の関数と、
前記タイムキーパー識別子で指定されるタイムキーパーに対して前記第５の関数を呼び出す第９の関数と、
前記タイムキーパー識別子で指定されるタイムキーパーに対して前記第１の関数を呼び出し、結果を戻り値として返す第１０の関数と、
前記タイムキーパー識別子で指定されるタイムキーパーに対して前記第６の関数を呼び出す第１１の関数とを、
有するタイムキーパー統合モジュールを設けたことを特徴とする請求項２または３記載のハード・ソフト協調検証用シミュレータ。
【請求項５】
前記各タイムキーパーに、
対応するスレッドの状態が休眠状態か動作状態かを示す第３の変数と、
前記第３の変数を休眠状態に設定する第１２の関数と、
前記第３の変数を動作状態に設定する第１３の関数と、
前記第３の変数を戻り値として返す第１４の関数とを、
設けたことを特徴とする請求項４記載のハード・ソフト協調検証用シミュレータ。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は、ハードウエア設計やシステムレベル設計における論理検証や、ハードウエアとソフトウエアの協調検証を高速化するためのＣ言語ベースのハード・ソフト協調検証用シミュレータに関するものである。
【背景技術】
【０００２】
従来、組み込みシステムのＣＰＵ（Central  Processing  Unit）、メモリ、バス、周辺デバイス等の動作を模擬したシミュレーション・モデル上で、リアルタイムＯＳ(Operation  System)、デバイスドライバ、アプリケーション・プログラム等からなるソフトウエア動作を検証する協調検証には、ＨＤＬ(Hardware  Description  Language)を用いたシミュレータが使用されていた。しかし、ＨＤＬを用いたシミュレータでは、高速化が困難なため、例えば下記非特許文献１に記載されるような、Ｃ言語ベースのモデル記述言語を用いたシステムレベルのシミュレータが提案され、使用されるようになってきている。シミュレーションを高速化することにより、ハードウエアの詳細設計やＬＳＩ(Large  Scale  Integration)設計が完了する前に、ソフトウエアを含めたシステムレベルの事前検証が可能になる。
【０００３】
通常のＣ言語では、ハードウエアの遅延時間やＣＰＵの実行サイクル数を反映したシミュレーションの実現が困難であるため、SpecCやSystemC等のハードウエアモデル記述用言語が提案され、標準化が進められている。
【０００４】
SystemCシミュレータでは、１つの起動中のタスクから起動できるスレッド(Thread)と呼ばれるより小さなモジュール単位で並行動作しているプロセスを実現している。また、SystemCシミュレータには、シミュレーション時刻を制御するためのwait関数が用意されている。wait関数は、SystemCシミュレータのカーネル（本体）で管理しているシミュレーション時刻を、wait関数呼び出しの引数として与えられた経過時間だけ進めると共に、並行して動作しているスレッド間のコンテキスト切り替えの制御を行うものである。なお、コンテキストとはシミュレーションを実行しているプロセッサの状態を指し、コンテキスト切り替えとは実行中のスレッドのコンテキストから別のスレッドのコンテキストに切り替えることを言う。
【０００５】
従って、SystemCシミュレータを使用して協調検証のシミュレーションを行う場合、並行動作を行うスレッドを、wait関数によって順次切り替えて制御することにより、ソフトウエアを含めたシステムレベルの検証を行うことができる。
【０００６】
【特許文献１】特開２００５−２９３２１９号公報
【特許文献２】特開２００６−２３８５２号公報
【非特許文献１】Open  SystemC  Initiative,”SystemC  2.0.1  Language  Reference  Manual”,Revision1.0
【発明の開示】
【発明が解決しようとする課題】
【０００７】
しかしながら、前記SystemCシミュレータを使用した協調検証のシミュレーションでは、wait関数を呼び出すたびにスレッド間のコンテキスト切り替え制御が行われることになるため、頻繁に行われるコンテキスト切り替え制御によってオーバーヘッドが大きくなり、シミュレーション速度の低下の一因となっている。
【０００８】
本発明は、コンテキスト切り替え制御のオーバーヘッドを減少させることによってシミュレーション時間を短縮することができる、SystemCシミュレータをベースとしたハード・ソフト協調検証用シミュレータを提供すること目的としている。
【課題を解決するための手段】
【０００９】
本発明は、ハードウエアとソフトウエアの協調検証を行うためのＣ言語ベースのハード・ソフト協調検証用シミュレータであって、ハードウエア及びソフトウエアに対応するシミュレーション・モデルを構成する複数のスレッド毎に設けられ、それぞれが対応するスレッドのシミュレーション時刻を制御するために、シミュレーション時刻を保持する第１の変数、積算時間を保持する第２の数、中断時刻と対応する中断メソッドを格納する中断要求待ち行列、及び処理用の関数を備えた複数のタイムキーパーと、これらのタイムキーパーからの要求に応じて、管理しているシステム時刻を与えられた要求時間だけ進めると共に、並行して動作している前記スレッド間のコンテキスト切り替えを制御するＣ言語ベースのシミュレータ本体とを備えたことを特徴としている。
【発明の効果】
【００１０】
本発明では、ミュレーション・モデルを構成する複数のスレッド毎に、各スレッドのシミュレーション時刻を保持するための第１の変数、積算時間を保持するための第２の変数、中断時刻と対応する中断メソッドを格納するための中断要求待ち行列、及び処理用の関数を備えたタイムキーパーを設けている。これにより、各スレッドのシミュレーション時刻が対応するタイムキーパーによって管理されるので、シミュレータ本体のwait関数を呼び出す頻度が減少し、このwait関数呼び出しに伴うコンテキスト切り替え制御のオーバーヘッドが減少してシミュレーション時間が短縮されるという効果がある。
【発明を実施するための最良の形態】
【００１１】
この発明の前記並びにその他の目的と新規な特徴は、次の好ましい実施例の説明を添付図面と照らし合わせて読むと、より完全に明らかになるであろう。但し、図面は、もっぱら解説のためのものであって、この発明の範囲を限定するものではない。
【実施例１】
【００１２】
図１は、本発明の実施例を示すシミュレータの構成図である。
このシミュレータ１０は、SystemCシミュレータをベースとしてハードウエアとソフトウエアの協調検証を行うもので、従来のSystemCシミュレータ１１の前段に複数のタイムキーパー１２を設けたものである。
【００１３】
このシミュレータ１０には、ハードウエアのシミュレーション・モデル１と、ソフトウエアのシミュレーション・モデル２が接続されるようになっている。
【００１４】
ハードウエアのシミュレーション・モデル１は、逐次的に実行されるＣＰＵや周辺デバイス毎にその機能をSystemC言語でモデル化したもので、デバイス毎に作成された複数のスレッドで構成される。また、ソフトウエアのシミュレーション・モデル２は、Ｃ言語で記述されたリアルタイムＯＳ、ドライバ、アプリケーション等のプログラムを、例えば、特許文献１に記載されたツールを利用して、SystemCモデルに変換した複数のスレッドで構成されている。
【００１５】
タイムキーパー１２は、逐次的に実行されるデバイスやプログラム毎に、そのシミュレーション時刻を制御するためのもので、例えば、複数のマルチタスク環境のＣＰＵでは、タスク間の実行制御が逐次的に行われるため、このＣＰＵのシミュレーション時刻を統一的に管理する１つのタイムキーパー１２が用意される。これに対して、複数のステートマシンが並列動作するようなデバイスに対しては、逐次的に実行される各ステートマシンをインプリメントするスレッド毎にタイムキーパー１２が用意される。
【００１６】
各デバイスやプログラムのスレッドに対応して用意されたタイムキーパー１２はチャネル接続され、各スレッドからチャネル接続されたポートを介して必要に応じて参照できるようになっている。
【００１７】
各タイムキーパー１２は、それぞれシミュレーション時刻Tsimを保持する変数Ｘと、積算時間Tsumを保持する変数Ｙと、中断時刻と対応する中断メソッドを格納する中断要求待ち行列Ｑと、current_timeメソッド、current_sc_timeメソッド、flush_timeメソッド、break_timeメソッド、sum_timeメソッド及びsync_timeメソッドの６個のメソッドを有している。
【００１８】
current_timeメソッド（第１の関数）は、現在のシミュレーション時刻Tsimを戻り値として返す関数である。
【００１９】
current_sc_timeメソッド（第２の関数）は、SystemCシミュレータのカーネルで管理しているシミュレーション時刻（以下、システム時刻Tsysと呼ぶ）に相当するTsim-Tsumの値を戻り値として返す関数である。
【００２０】
flush_timeメソッド（第３の関数）は、積算時間Tsumを引数とするSystemCシミュレータのwait関数を呼び出した後、その積算時間Tsumをゼロクリアする関数である。なお、フラッシュ(flush)とは、ゼロクリアを意味する。
【００２１】
break_timeメソッド（第４の関数）は、引数として与えられた中断時刻bTsim、中断システム時刻bTsys、及び中断メソッドを中断要求として、タイムキーパーの中断要求待ち行列Ｑに登録する関数である。ここで、中断メソッドは、sum_timeメソッドにおいてシミュレーション時刻Tsimが中断時刻bTsim以上になった場合に呼び出される関数を示している。複数のバスマスタが同一周辺デバイスに対して、中断時刻と対応する中断メソッドを登録する場合に対応するため、これらは中断要求待ち行列Ｑとして管理されている。中断要求待ち行列Ｑの先頭には最も小さい中断時刻が格納され、中断時刻が大きくなる順序で格納されるようになっている。なお、初期化時に、中断要求待ち行列Ｑの内容は空に設定される。
【００２２】
sum_timeメソッド（第５の関数）は、中断要求待ち行列Ｑの状態に従って次の処理を行う関数である。
【００２３】
中断要求待ち行列Ｑが空の場合、シミュレーション時刻Tsimに経過時間timeを加算してこのシミュレーション時刻Tsimを進めると共に、積算時間Tsumに経過時間timeを加算してこの積算時間Tsumを更新する。
【００２４】
中断要求待ち行列Ｑが空でない場合は、シミュレーション時刻Tsimと中断要求待ち行列Ｑにおける先頭中断要求の中断時刻bTsimの関係により、処理が異なる。
【００２５】
シミュレーション時刻Tsimが中断時刻bTsim未満の場合、シミュレーション時刻Tsimに経過時間timeを加算してこのシミュレーション時刻Tsimを進めると共に、更新したシミュレーション時刻Tsimが中断システム時刻bTsysより小さいときは積算時間Tsumをゼロクリアし、そうでないときは積算時間Tsumを(Tsim-bTsys)の値に設定する。
【００２６】
シミュレーション時刻Tsimが中断時刻bTsim以上の場合、中断要求待ち行列Ｑの内で中断時刻bTsimがシミュレーション時刻Tsim以上であるすべての中断要求に対し、積算時間Tsumを(Tsim-bTsys)の値に設定して中断メソッドを呼び出した後、これらの中断要求を待ち行列Ｑから削除する。その後、シミュレーション時刻Tsimに経過時間timeを加算してこのシミュレーション時刻Tsimを進めると共に、積算時間Tsumに経過時間timeを加算してこの積算時間Tsumを更新する。
【００２７】
sync_timeメソッド（第６の関数）は、引数として与えられるシミュレーション時刻sTsimとタイムキーパーの現在のシミュレーション時刻Tsimを比較し、Tsim＜sTsimの場合にsTsimと更新後のTsimの差分を引数としてsum_timeメソッドを呼び出す関数である。これにより、シミュレーション時刻TsimはsTsimの値に更新され、積算時間Tsumは(Tsum-sTsim-Tsim)の値に更新される。なお、Tsim≧sTsimの場合には、sum_timeメソッドの呼び出しは行われない。
【００２８】
上記の積算時間Tsumは、タイムキーパー１２で更新しているシミュレーション時刻TsimとSystemCシミュレータ１１のwait関数呼び出しによって更新されるシステム時刻Tsysとの差分時間を示している。従って、flush_timeメソッドを呼び出して積算時間Tsumをゼロクリアしたときには、シミュレーション時刻Tsimとシステム時刻Tsysは一致する。また、中断要求待ち行列Ｑが空であるとき、sum_timeメソッドは積算時間Tsumと経過時間timeを加算した値によってこの積算時間Tsumを更新する。
【００２９】
このシミュレータ１０では、各デバイスがシミュレーション時刻をSystemCシミュレータ１１のwait関数を呼び出して進めるのではなく、そのデバイスのタイムキーパーtikに対して、tik->
sum_timeメソッド呼び出しを行うことによって進めるようになっている。
【００３０】
他のデバイスに制御を切り替えたい場合は、現在実行中のデバイスのタイムキーパーtikに対して、tik->
flush_timeメソッド呼び出しを行う。これにより、タイムキーパーtikの積算時間Tsumを引数とするSystemCシミュレータ１１のwait関数を呼び出しが行われる。このwait関数呼び出しにより、SystemCシミュレータ１１のカーネル内で管理している実行中のデバイスのシステム時刻Tsysが積算時間Tsumで指定される時間だけ進められると共に、実行可能なデバイスの内で最もシステム時刻Tsysの小さいデバイスに制御が渡されるコンテキスト切り替え制御が行われる。
【００３１】
デバイス間でシミュレーション時刻を同期させる必要がある場合、sync_timeメソッド呼び出しを行う。あるデバイスのタイムキーパーdtikのシミュレーション時刻を、他のデバイスのタイムキーパーstikの現在のシミュレーション時刻に設定する場合、dtik->sync_time(stik->current_timeメソッド)メソッド呼び出しを行う。つまり、sTsim=stik->current_timeメソッド呼び出しによってタイムキーパーstikの現在のシミュレーション時刻sTsimを求め、このsTsimを引数としてdtik->
sync_timeメソッド呼び出しを行うことにより、タイムキーパーdtikのシミュレーション時刻がsTsimに設定される。
【００３２】
デバイスのタイムキーパーdtikに対して中断時刻bTsim、中断システム時刻bTsys、及び中断メソッドを中断要求として登録する場合、tik->break_timeメソッド呼び出しを行う。これにより、タイムキーパーtikにおいてtik->sum_timeメソッド呼び出しを行ってシミュレーション時刻の更新を行う前に、このタイムキーパーtikのシミュレーション時刻が中断時刻bTsim以上に達した場合、TikIFクラス内で定義された中断メソッドの呼び出しが行われる。中断メソッドとしてflush_timeメソッドを指定した場合には、この中断メソッド呼び出しによって他のデバイスへのコンテキスト切り替え制御が行われる。
【００３３】
以下、具体例を用いて図１のシミュレータ１０の動作を説明する。なお、以下の説明におけるシミュレーション記述言語は、Ｃ言語に準じている。
【００３４】
（Ａ）sum_timeメソッドの機能
デバイスにおけるシミュレーション時刻の制御は、そのデバイスに対応したタイムキーパーに対してsum_timeメソッド呼び出しを行うことによって実現される。
【００３５】
例えば、ＣＰＵとそのタイムキーパーctikをチャネル接続するために、SystemCシミュレータにおいて次のようなＣＰＵクラスを定義する。
class  cpu:public  sc_module
{
public:
sc_port<tikIF,0>ctik  //port  to  ＣＰＵ  Time  Keeper
SC_CTOR(CPU){
SC_THREAD(main);
}
void  main(void)
}
【００３６】
ここで、tikIFはタイムキーパーのメソッド関数を定義するインタフェース定義で、例えば以下のように定義される。
class  tikIF:public  sc_interface{
public:
virtual  void  break_time(uint64  bTsim,uint64  bTsys,void(TikIF::*method)())=0;
virtual  void  flush_time(void)=0;
virtual  void  sum_time(long  time)=0;
virtual  uint64  current_time(void)=0;
virtual  void  sync_time(uint64  sTsim)=0;
};
【００３７】
上記のＣＰＵクラス定義における以下の記述は、tikIFインタフェースを持つ任意の数のチャネルをtikポートに接続可能であることを意味する。
sc_port<tikIF,0>ctik;  //port  to  CPU  Time  Keeper
【００３８】
また、ＣＰＵクラス定義における以下の記述は、シミュレーション開始時にmain関数をＣＰＵスレッドとして起動することを意味している。
SC_CTOR(CPU){
SC_THREAD(main);
}
【００３９】
ＣＰＵとタイムキーパーctikの接続は、これらのクラス定義の上位階層において以下のように行う。
cpu  =new  cpu(“cpu”);  //ＣＰＵを生成
ctik  =new  tik(“ctik”);  //ＣＰＵ用タイムキーパーを生成
cpu->tik(*ctik);      //ＣＰＵにＣＰＵ用タイムキーパーを接続
【００４０】
ＣＰＵのtikポートに接続されたどのタイムキーパーを参照するかは、上位階層においてタイムキーパーが接続された順に、tik[0],tik[1],…のように指定する。また、どのタイムキーパーを参照するかを指定するためのタイムキーパー識別氏のデータタイプtid_tを、例えば、以下のように定義する。
typedef  enum{C_TID=0,P_TID=1,…
}  tid_t;
【００４１】
ここで、C_TIDとP_TIDは、それぞれＣＰＵとの周辺デバイスのタイムキーパー識別子である。このようにして、tikポートへのタイムキーパーの接続を、tid_tで定義しているタイムキーパー識別子の番号順に、ＣＰＵのタイムキーパー、周辺デバイスのタイムキーパー、…のように接続すれば、tik[C_TID]はＣＰＵのタイムキーパーを参照し、tik[P_TID]は周辺デバイスのタイムキーパーを参照するということになる。
【００４２】
上記の上位階層におけるＣＰＵへのタイムキーパーの接続では、ＣＰＵにタイムキーパーctikのみしか接続されないので、tik[C_TID]ポートを介したアクセスのみが可能である。これにより、ＣＰＵのmainスレッドからtik[C_TID]ポートを介してＣＰＵのタイムキーパーctikのメソッド呼び出しが可能になる。
【００４３】
図２は、ＣＰＵのmainスレッド切り替え制御の説明図であり、縦軸はシミュレーション時刻を示している。
【００４４】
経過時間cT1,cT2,…,cTkは、ＣＰＵにおける命令実行時間で、ＣＰＵモデルとして例えば、命令セットシミュレータを使用する場合には、実行される各命令の実行時間となる。この場合、ＣＰＵのmainスレッド関数は、以下のように定義される。
void  CPU::main(void){
tik[C_TID]->sum_time(cT1);
tik[C_TID]->sum_time(cT2);
tik[C_TID]->sum_time(cTK);
}
【００４５】
ＣＰＵのmainスレッドは、ctikポートを介してtik[C_TID]->sum_time(cT1),tik[C_TID]->sum_time(cT2),…,tik[C_TID]->sum_time(cTK)メソッドを呼び出すことにより、シミュレーション時刻Tsimを進める。この図に示すように、ＣＰＵスレッドがｉ番目の経過時間cTiを引数とするtik[C_TID]->sum_time(cTi)メソッドを呼び出すと、ctikのsum_timeメソッドにおいて、積算時間Tsumとシミュレーション時刻Tsimに、cTiの値が加算される。
【００４６】
tik[C_TID]->sum_time(cTK)メソッド呼び出しの後の積算時間cTsumKと、シミュレーション時刻cTsimKは次式で与えられる。
cTsumK=cT1+cT2+…+cTK
cTsimK=cTsum0+cTsumK=cT0+cT1+cT2+…+cTK
【００４７】
ここで、cTsum0は、tik[C_TID]->sum_time(cT1)メソッドを呼び出す前のシミュレーション時刻である。このように、スレッド内のシミュレーション時刻制御をSystemCシミュレータのwait関数呼び出しではなく、タイムキーパーのsum_timeメソッド呼び出しで行うことで、スレッド間のコンテキスト切り替え制御が省略され、シミュレーションが高速化される。
【００４８】
（Ｂ）スレッド間の同期制御
ハードウエアとソフトウエアの協調検証環境では、ＣＰＵ、メモリ、周辺デバイスがバス経由で接続され、ＣＰＵ上で動作するソフトウエアと周辺デバイスが協調して動作しながら処理を進める。バスに接続されるデバイスには、このバスに対して能動的にデータ転送を開始できるバスマスタと、受動的にバス要求を待つバススレーブがある。通常、ＣＰＵがバスマスタとなってデータ転送バス要求を出力し、バス経由でバススレーブであるメモリや周辺デバイスにアクセスすることで処理が進められる。ここでは、バスを経由したデータ転送のモデルを、トランザクションレベルでモデル化する場合の例を説明する。
【００４９】
バスマスタからのバス要求が発生した場合、バスアービタによってバス使用権を獲得した後、バススレーブへのアクセスが行われる。バススレーブへアクセスを行う場合のシミュレーション時刻の更新は、バスマスタのタイムキーパーに対して行う。バススレーブ側でどのバスマスタのタイムキーパーに対してシミュレーション時刻制御を行えば良いかを識別するため、バス要求を行うメソッドにバスマスタのタイムキーパーの識別子を引数として付加する。
【００５０】
例えば、ＣＰＵがバスマスタとなって、バススレーブである周辺デバイスへアクセスする場合、周辺デバイスはＣＰＵのタイムキーパーctikに対して、tik[C_TID]->sum_time(Tacc)メソッドを呼び出してＣＰＵのシミュレーション時刻を進める。ここで、Taccは、周辺デバイスのアクセス時間である。つまり、このメソッド呼び出しによって、周辺デバイスのアクセス時間TaccがＣＰＵのシミュレーション時刻に加算され、ＣＰＵのシミュレーション時刻が進められる。
【００５１】
ＣＰＵがバスマスタとなってバス経由で周辺デバイスへアクセスし、周辺デバイスのスレッド動作を起動する場合、周辺デバイスのスレッドが起動した後、ＣＰＵにおけるソフトウエアの実行と周辺デバイスにおけるハードウエア動作が並行して行われる。つまり、周辺デバイスの起動後、ＣＰＵのタイムキーパーを用いたシミュレーション時刻制御と周辺デバイスのタイムキーパーを用いたシミュレーション時刻制御が独立して行われる。
【００５２】
この場合、周辺デバイスのスレッドの起動時刻をＣＰＵによる周辺デバイスの起動時刻に設定し、この周辺デバイスのシミュレーション時刻をＣＰＵのシミュレーション時刻に同期させる必要がある。このために用意されたものがsync_timeメソッドである。周辺デバイスは、スレッドを起動する際にcurrent_timeメソッドによってＣＰＵのタイムキーパーのシミュレーション時刻を取り出し、取り出したシミュレーション時刻を引数として周辺デバイスのタイムキーパーに対してsync_timeメソッド呼び出しを行うことでシミュレーション時刻を設定する。
【００５３】
このようなシミュレーション時刻の同期制御を行うために、周辺デバイスにＣＰＵと周辺デバイスの両方のタイムキーパーをチャネル接続する必要がある。このため、ＣＰＵの場合と同様に、以下のような周辺デバイスクラスpdevを定義する。
class  pdev:  public  sc_module
{
public:
sc_port<tikIF,0>tik;  //タイムキーパーアクセスのためのポート
sc_port<busIF>bus;    //バスアクセスのためのポート
SC_CTOR(pdev){
SC_THREAD(main);
}
}
【００５４】
同様にバスbusのクラスを定義し、ＣＰＵや周辺デバイスpdevとＣＰＵのタイムキーパーctikや周辺デバイスpdevのタイムキーパーPtikの接続、及びバスbusとの接続は、上位階層において以下のように行う。
cpu  =new  cpu(“cpu”);  //ＣＰＵを生成
pdev  =new  pdev(“pdev”);  //周辺デバイスを生成
bus  =new  bus(“bus”);  //バスを生成
ctil  =new  tik(“ctik”);  //ＣＰＵ用タイムキーパーを生成
ptic  =new  tik(“ptik”);  //周辺デバイス用タイムキーパーを生成
cpu->bus(*bus);  //ＣＰＵにバスを接続
cpu->tik(*ctik);  //ＣＰＵにＣＰＵ用タイムキーパーを接続
bus->pdev->(*pdev);  //バスに周辺デバイスをスレーブとして接続
bus->tik(*ctik);  //バスにＣＰＵ用タイムキーパーを接続
bus->tik(*ptik);  //バスに周辺デバイス用タイムキーパーを接続
pdev->bus(*bus);  //周辺デバイスにバスを接続
pdev->tik(*ctik);  //周辺デバイスにＣＰＵ用タイムキーパーを接続
pdev->tik(*ptik);  //周辺デバイスに周辺デバイス用タイムキーパーを接続
【００５５】
この場合、バスbusや周辺デバイスpdevのタイムキーパーポートには、最初にＣＰＵ用タイムキーパーctikが接続され、次に周辺デバイス用タイムキーパーpdevが接続される。従って、まずtik[0]（つまり、tik[C_TID]）によってタイムキーパーctikが参照可能となり、次にtik[1]（つまり、tik[P_TID]）によってタイムキーパーptikが参照可能となる。これにより、バスや周辺デバイスから、ＣＰＵ用タイムキーパーctikと周辺デバイス用タイムキーパーptikの双方のメソッドを呼び出すことが可能になる。
【００５６】
例えば、データ書き込み転送用writeメソッドをバスと周辺デバイスに定義し、ＣＰＵがバス経由で周辺デバイスのレジスタへ書き込みを行うためのbus->writeメソッド呼び出しを行って、周辺デバイスを起動する場合を説明する。ここでは、書き込みを行うレジスタのアドレスaddress、書き込みデータdata、及びwriteメソッドを実行したＣＰＵのタイムキーパー識別子C_TIDが、引数として使用される。この場合、ＣＰＵがバスマスタであるので、writeメソッドを実行したバスマスタのタイムキーパーはctikとなる。
【００５７】
図３は、ＣＰＵからの周辺デバイススレッドの起動制御の説明図である。この図３に示すように、ＣＰＵスレッドは、bus->write(address,data,C_TID)メソッド呼び出しを行い、バスモデルを起動する。バスモデルにおけるwriteメソッドの記述例は次のようになる。
void  bus::(long  address,long  data,tid_t  tid){
addressをデコードして周辺デバイスpdevを選択し、
バスアービタによりバス権を獲得；
pdev->write(address,data,tid);
}
【００５８】
ここで、tidはバス要求を出力したバスマスタのタイムキーパー識別子で、この場合はbus->write(address,data,C_TID)メソッド呼び出しによって与えられたＣＰＵのタイムキーパー識別子C_TIDとなる。このwriteメソッドは、まず、アドレスaddressをデコードして周辺デバイスpdevを選択し、バスアービタによってバス使用権を獲得した後、周辺デバイスpdevに対してpdev->write(address,data,tid)メソッド呼び出しを行ってアドレスaddressで指定されるレジスタに対してデータdataの書き込みを行う。
【００５９】
また、周辺スレッドのスレーブ動作の記述例は次のようになる。
/*周辺デバイスにおけるwriteメソッドの記述例*/
void  pdev::write(long  address,long  data,tid_t  tid){
tid[tid]->sum_time(Tacc);
addressで指定されるレジスタにdataの書き込みを行う；
if(上記書き込みによって周辺デバイスが起動される場合)｛
tik[P_TID]->sync_time(tik[tid]->current_time());
notify(pdev_start);
}
}
【００６０】
上記のようにＣＰＵがバスアービタによってバス使用権を獲得した後、周辺デバイスpdevのmainスレッドを起動する前にsync_timeメソッド呼び出しを行い、周辺デバイスのタイムキーパーのシミュレーション時刻をＣＰＵが書き込みを完了したシミュレーション時刻sTsimに設定する必要がある。
【００６１】
周辺デバイスは、tid[tid]->sum_time(Tacc)メソッド呼び出しにより、ＣＰＵのシミュレーション時刻をTaccで指定されるアクセス時間だけ進める。ＣＰＵからの書き込み処理が完了した時点で、先ず、sTsim=tik[tid]->current_timeメソッド呼び出しを行ってＣＰＵの現在のシミュレーション時刻sTsimを求め、周辺デバイスのタイムキーパーptikに対してtik[P_TID]->sync_time(sTsim)メソッドを呼び出して周辺デバイスのシミュレーション時刻をＣＰＵのシミュレーション時刻sTsimに設定する。
【００６２】
その後、周辺デバイスのスレッドをSystemyCシミュレータのnotify（イベント）関数呼び出しによって起動する。ここで、notify（イベント）関数は、wait（イベント）関数によって指定されたイベントを待っているスレッドが有る場合、そのスレッド動作を起動する。
【００６３】
周辺デバイスpdevのmainスレッドは、例えば、次のように記述する。
void pdev::main(){
for(;;){      //以下の処理を繰り返す
Wair(pdev_start);  //notify(pdev_start)が実行されるまで待つ
tik[P_TID]->sum_time(pT1);  //ptikのシミュレーション時刻に経過時間pT1を加算
tik[P_TID]->sum_time(pT2);  //ptikのシミュレーション時刻に経過時間pT2を加算
tik[P_TID]->sum_time(pTL);  //ptikのシミュレーション時刻に経過時間pTLを加算
}
}
【００６４】
上記の周辺デバイスのスレッドは、起動された後、wait(pdev_start)関数呼び出しによってpdev_startイベントを待つ。この待ち状態は、上記の周辺デバイスにおけるwriteメソッドにおけるnotify(pdev_start)関数呼び出しが行われた時点で解除される。
【００６５】
このように、ＣＰＵは、周辺デバイスのスレッドを起動した後、その周辺デバイスの動作状況を確認する処理が必要になることがある。周辺デバイスの動作状況の確認には、大別して、ＣＰＵが周辺デバイスの特定のレジスタ（例えば、状態レジスタ）の内容を読み出して確認するポーリングと、周辺デバイスがＣＰＵに対して割り込み通知する割り込みの２つの方法がある。
【００６６】
（Ｃ）ポーリング
ポーリングは、周辺デバイスがその動作状況に応じて特定のレジスタの内容を更新し、ＣＰＵがバス経由でその特定のレジスタの内容を読み出すためのreadメソッドを呼び出すことで実現される。
【００６７】
図４は、ポーリングによるＣＰＵと周辺デバイス間のスレッドの切り替え制御の説明図である。
【００６８】
この例では、周辺デバイスpdevのmainスレッドが起動された後、経過時間pT1,pT2,…,pTLの順にシミュレーション時刻を進める場合を示している。ここで、経過時間pT1,pT2,…,pTLは、周辺デバイスにおける処理時間である。例えば、周辺デバイスをステートマシンとしてインプリメントしている場合には、これらの経過時間は各ステートの滞在時間となる。
【００６９】
周辺デバイスのmainスレッドは、そのタイムキーパーptikに対して、tik[P_TID]->sum_time(pT1),tik[P_TID]->sum_time(pT２),…,tik[P_TID]->sum_time(pTL)メソッドを呼び出す。tik[P_TID]->sum_time(pTL)メソッド呼び出し後の積算時間pTsumLと、シミュレーション時刻pTsimLは次式で与えられる。
pTsumL=pT1+pT2+…+pTL
pTsimL=pTsum0+pTsumL=pT0+pT1+pT2+…+pTL
【００７０】
ここで、pTsum0は、tik[P_TID]->sum_time(pT1)メソッドを呼び出す前のシミュレーション時刻である。
【００７１】
ＣＰＵは、周辺デバイススレッドを起動するbus->writeメソッドを読み出した後、経過時間cT1,cT2,…,cTKの順にシミュレーション時刻を進める。
【００７２】
ここで、ＣＰＵのmainスレッドがtik[C_TID]->sum_time(cTK)メソッド呼び出しを行った後、bus->read(address,C_TID)メソッド呼び出しを行い、周辺デバイスのレジスタの内容を読み出したとする。readメソッドは、読み出しを行うレジスタのアドレスaddress、及びreadメソッドを実行したバスマスタのタイムキーパー識別子を引数として持ち、読み出したデータを戻り値として返す。この場合、ＣＰＵのmainスレッドがバスマスタであるので、readメソッドを実行したバスマスタのタイムキーパー識別子はC_TIKとなる。
【００７３】
ＣＰＵのmainスレッドにおけるtik[C_TID]->sum_time(cTK)メソッド呼び出し後のタイムキーパーctikのシミュレーション時刻をcTsimKとし、以下の関係が成立するものとする。
pTsim0+(pT1+pT2+…+pTL-1)≦cTsimK≦pTsimL=pTsim0+(pT1+pT2+…+pTL)
【００７４】
この場合、バスアービタでは、下記に示すように周辺デバイスのタイムキーパーに対して、ＣＰＵのシミュレーション時刻、ＣＰＵのシステム時刻、及びflish_timeメソッドを引数としてbreak_timeメソッド呼び出しを行い、中断要求として登録する。これにより、周辺デバイスのシミュレーション時刻が、中断時刻として設定したＣＰＵのシミュレーション時刻に達したとき、中断メソッドであるflush_timeメソッドが呼び出される。
tik[P_TID]->break_time(tik[C_TID]->currenttime()
,tik[C_TID]->current_sc_time()
,&TikIF::flush_time);
tik[C_TID]->flush_time();
【００７５】
上記のbreak_timeメソッドは、まず、タイムキーパー識別子C_TIDで指定されるＣＰＵのタイムキーパーに対するcurrent_timeメソッドとcurrent_sc_timeメソッド呼び出しを行い、それぞれＣＰＵの現在のシミュレーション時刻cTsimKとシステム時刻Tsysを求める。そして、周辺デバイスのタイムキーパーptikに対してcTsimKを中断時刻、Tsysを中断システム時刻として登録する。このときの対応する中断メソッドが、周辺デバイスのタイムキーパーptikに対するflush_timeメソッドであることを意味する。
【００７６】
break_timeメソッドの呼び出し後に実行されるＣＰＵのタイムキーパーctikに対するflish_timeメソッド呼び出しでは、SystemyCシミュレータのwait関数呼び出しを行って他のスレッドへのコンテキスト切り替えを行い、そのスレッドに制御を渡す。このflush_timeメソッドの呼び出しにより、周辺デバイススレッドへ制御が渡され、周辺デバイススレッドによるwait(notify)メソッド呼び出し以降の処理が実行される。
【００７７】
周辺デバイススレッドは、tik[P_TID]->sum_time(pT1),tik[P_TID]->sum_time(pT２),…,tik[P_TID]->sum_time(pTL)メソッド呼び出しにおいて、シミュレーション時刻がＣＰＵからのbreak_timeメソッドによって設定された中断時刻の値cTsimK以上に達したかどうかを調べる。周辺デバイスのタイムキーパーptikのシミュレーション時刻が中断時刻の値cTsimKに達しない場合、周辺デバイススレッドの実行が継続される。シミュレーション時刻がcTsimK以上に達した場合、つまり、シミュレーション時刻がpTsimLに達した場合、タイムキーパーptikは、対応する中断メソッドを呼び出してＣＰＵスレッドへ制御を切り替える。これにより、ＣＰＵスレッドのbus->readメソッド呼び出し以降の処理が実行される。このような制御により、ＣＰＵスレッドからのbus->readメソッド呼び出しは、周辺デバイススレッドのシミュレーション時刻に同期して実行される。
【００７８】
（Ｄ）バスアービタ動作
バスには、複数のバスマスタが接続されることがある。例えば、複数のＣＰＵ間でバスを共有するときに、ＤＭＡＣ(Direct  Memory  Access  Controller)のようにバスマスタとなり得る周辺デバイスをバスに接続する場合である。このような場合、複数のバスマスタ間のバス要求を調停するためのバスアービタが必要になる。
【００７９】
バスアービタは、複数のバスマスタからバス要求が同時に発生したときに、バス仕様によって予め指定された優先度判定条件に基づいて最も優先度の高いバスマスタを選択し、そのバスマスタにバス使用権を与えるものである。優先度判定条件としては、バスマスタに固有の優先度を設定する方法や、バスマスタ間で優先度を巡回させる方法等が使われている。
【００８０】
バス使用権が与えられたバスマスタは、バスを使用してバススレーブをアクセスする。バス使用権が与えられたバスマスタがバスを使用している間、それ以外のバスマスタは、バス使用権の待ち状態となる。
【００８１】
このようなバス調停機能を実現するため、シミュレーション・モデルにおいては、各バスマスタはそれぞれ独立したスレッドとして実現され、各バスマスタにはタイムキーパーが用意される。バスマスタは、バスアービタに対してそのタイムキーパーを引数としてread/writeメソッド呼び出しを行うことによりバス要求を出力する。
【００８２】
バスアービタは、バス要求が発生したときに以下のステップ（１）〜（６）の手順でバス調停を行う。
【００８３】
(1)  バス要求の引数として与えられたアドレスを判別し、アクセスするバススレーブを決定し、下記に示すようにバスマスタのタイムキーパー識別子m_tidを引数として、バススレーブのタイムキーパーに対してbreak_timeメソッド呼び出しを行う。これにより、バスマスタのシミュレーション時刻をバススレーブのタイムキーパーの中断時刻bTsimとして登録する。このときの対応するメソッドは、バススレーブのタイムキーパーに対するflush_timeメソッドである。この動作の記述例を以下に示す。
アドレスをデコードし、バススレーブのタイムキーパー識別子s-tidを決定;
tik[s_tid]->break_time(tik[m_tid]->current_time()
,tik[m_tid]->current_sc_time()
,&TikIF::flush_time);
【００８４】
(2)  バス要求、タイムキーパー識別子、及びバスマスタのシミュレーション時刻をバスアービタ内部のバス要求待ち行列に格納する。
【００８５】
(3)  引数として渡されたバスマスタのタイムキーパー識別子の指すタイムキーパーに対して、flush_timeメソッドを実行して積算時間Tsumの値をゼロクリアする。これにより、他のバスマスタのスレッドへのコンテキスト切り替えが行われる。他のバスマスタがバス要求を出力中である場合、バスマスタのスレッドへのコンテキスト切り替えにより、制御が渡されたバスマスタは、ステップ(1)からの処理を実行する。
【００８６】
(4)  バス要求待ち行列に格納された最も小さいシミュレーション時刻を持つバス要求の内で、最も優先度の高いバス要求を選択する。
【００８７】
(5)  選択したバス要求のタイムキーパー識別子が、今回のバス要求の引数として与えられたタイムキーパー識別子と一致したとき、次のステップ(6)へ進む。そうでないとき、即ち、他のバスマスタのバス要求が選択されたときは、バスマスタのスレッドを待ち状態にする。この待ち状態は、ステップ(6)で解除される。待ち状態が解除された後、ステップ(4)へ進む。
【００８８】
(6)  選択したバス要求によるバススレーブのアクセスが完了してバスが解放されるまで、バスを占有する。バス開放時点で、他のバスマスタの待ち状態をnotifyメソッドによって解除する。
【００８９】
上記手順により、ステップ(3)におけるflush_timeメソッドの実行で、ある時刻に実行されたすべてのバスマスタのバス要求が待ち行列に格納され、ステップ(4)において、最も優先度の高いバス要求が選択される。
【００９０】
図５及び図６は、それぞれバスアービタによるＣＰＵと周辺デバイス間のスレッドの切り替え制御(１及び２)の説明図である。
【００９１】
この図５では、ＣＰＵスレッドと周辺スレッドの２つのバスマスタがバスに接続され、ＣＰＵスレッドがbus->writeメソッドによってデータの書き込みアクセスを行うためのバス要求を出力し、周辺デバイススレッドがbus->readメソッドによってデータの読み出しアクセスを行うためのバス要求を出力する場合を示している。
【００９２】
ここでは、ＣＰＵのmainスレッドが経過時間cT1,cT2,…,cTKの順にシミュレーション時刻を進めた時点で、bus->writeメソッドの呼び出しを行い、周辺スレッドが経過時間pT1,pT2,…,pTLの順にシミュレーション時刻を進めた時点で、bus->readメソッドの呼び出しを行うものとする。また、tik[C_TID]->sum_time(cTK)メソッド呼び出し後のタイムキーパーctikのシミュレーション時刻をcTsimK、tik[P_TID]->sum_time(pTL)メソッド呼び出し後のシミュレーション時刻をpTsimL、tik[P_TID]->sum_time(pT1)メソッド呼び出し前のシミュレーション時刻をpTsim0とする。
【００９３】
ＣＰＵのスレッドがbus->writeメソッドの呼び出しを行った時点で、バスアービタが起動される。バスアービタは、ステップ（２）においてバス要求を待ち行列に格納し、ステップ(3)においてtik[C_TID]->flush_timeメソッドの呼び出しを行う。これにより、SystemyCシミュレータのwait関数呼び出しが行われる。このとき、cTsimKがpTsim0よりも大きいと、SystemyCシミュレータのカーネルは、周辺デバイスのスレッドへコンテキスト切り替えを行い、周辺デバイスのスレッドへ制御が渡される。
【００９４】
コンテキスト切り替えによって制御が渡された周辺デバイスのスレッドが、bus->readメソッドの呼び出しを行った時点でバスアービタが起動される。バスアービタは、ステップ(2)においてバス要求を待ち行列に格納し、ステップ(3)においてtik[PJID]->flush_time()メソッドの呼び出しを行う。これにより、SystemCのwait関数呼び出しが行われ、必要に応じてスレッド間のコンテキスト切り替えが行われる。
【００９５】
図５に示すように、cTsimKがpTsimLよりも小さい場合、バスアービタにおけるtik[P_TID]->flush_timeメソッド呼び出しにより、再度、ＣＰＵスレッドヘのコンテキスト切り替えが発生する。同図の折れ線で示している実線矢印は、このようなスレッド間の制御の流れを示している。バスアービタはステップ(4)において、最も優先度の高いバス要求を待ち行列から選択する。この場合、ＣＰＵのスレッドが要求したbus->writeメソッドの呼び出しが選択され、ＣＰＵによるバスアクセスが行われた後、以降のＣＰＵスレッドのtik[C_TID]->sum_time(cTK+1),tik[C_TID]->sum_time(cTK+2),…メソッド呼び出しの処理が行われる。
【００９６】
図６は、図５と同様のスレッド実行制御が行われる場合に、cTsimKがpTsimLよりも大きい場合を示している。このとき、tik[P_TID]->sum_time(pTL)メソッドを呼び出した後のbus->readメソッド呼び出しでは、バスアービタにおけるtik[P_TID]->flush_timeメソッドの呼び出しによるコンテキスト切り替えは発生しない。
【００９７】
バスアービタはステップ(4)において、最も優先度の高いバス要求を待ち行列から選択する。この場合、周辺デバイスのスレッドが要求したbus->readメソッドの呼び出しが選択され、周辺デバイスのスレッドによるバスアクセスが行われた後、以降の周辺デバイススレッドのtik[P_TID]->sum_time(pTL+1),tik[P_TID]->sum_time(pTL+2),…メソッド呼び出し処理が行われる。図６中の折れ線で示している実線矢印は、このようなスレッド間の制御の流れを示している。
【００９８】
周辺デバイスが処理を進め、tik[P_TID]->flush_timeメソッド呼び出しを行った時点で、図６中の折れ線で示している破線矢印で示すように、再度、ＣＰＵスレッドにコンテキスト切り替えが行われ、bus->writeメソッドによるアクセスが処理される。
【００９９】
cTsimKがpTsimLと等しい場合、バスアービタにおけるtik[P_TID]->flush_time()メソッドの呼び出しによってＣＰＵスレッドヘのコンテキスト切り替えが発生するか否かは、使用しているシミュレータに依存する。
【０１００】
ＣＰＵスレッドヘのコンテキスト切り替えが発生しなかった場合、バスアービタはステップ(4)において、待ち行列に格納された同一シミュレーション時刻に発行された２つのバス要求(即ち、ＣＰＵのスレッドからのbus->writeメソッドによるバス要求と、周辺デバイスのスレッドからのbus->readメソッドによるバス要求)の内で優先度の高いバス要求を選択する。
【０１０１】
ステップ(4)において、ＣＰＵのスレッドのバス要求の優先度が、周辺デバイスのスレッドのバス要求の優先度よりも高い場合、周辺デバイスのスレッドは、ステップ(5)で選択されたバス要求が自タイムキーパーの発したバス要求でないことを知り、ＣＰＵのスレッドのバス要求が完了するまで待ち状態となる。これにより、ＣＰＵスレッドヘのコンテキスト切り替えが行われる。この場合、スレッド間の制御の流れは図５と同様となる。
【０１０２】
逆に、ステップ(4）において、ＣＰＵのスレッドのバス要求の方が周辺デバイスのスレッドのバス要求よりも優先度が低いと、周辺デバイスのスレッドは、ステップ(5）において、選択されたバス要求が自タイムキーパーの発したバス要求であることを知り、周辺デバイスのスレッドによるバスアクセスが行われた後、以降の周辺デバイスの処理が行われる。この場合、スレッド間の制御の流れは図６と同じである。
【０１０３】
（Ｅ１）割り込み制御（その1）
スレッドの起動後、外部からの非同期イベントの発生をスレッドに通知したい場合がある。例えば、ＣＰＵが周辺デバイスを起動した後、周辺デバイスが割り込み信号によってＣＰＵに割り込みを発生させ、周辺デバイスの状態をＣＰＵに通知したいような場合である。
【０１０４】
割り込み信号は、通常、周辺デバイスの一種である割り込みコントローラに通知される。割り込みコントローラは、割り込み信号が通知された際、割り込み許可の判定や割り込みの優先順位判定を行い、発生した割り込みが許可されており、その割り込みの優先度が最も高いときＣＰＵに割り込みを通知し、このＣＰＵに設けられた割り込みハンドラを起動する。
【０１０５】
割り込みハンドラは、周辺デバイスからの割り込み要求が発生したときに実行されるＣＰＵの制御ソフトウエアで、下記のようにＣＰＵのスレッドとして実現される。
class  cpu:public  sc_module
｛
public:
sc_port<tikIF>ctik;  //  port  to  CPU  Time  Keeper
SC_CTOR（CPU）｛
SC_THREAD(main）;  //mainスレッドを起動
SC_THREAD(inthdr）;  //割り込みハンドラを起動
｝
void  main(void)；
void  inthdr(void)；
｝
【０１０６】
以下、周辺デバイスが割り込みによってＣＰＵの割り込みハンドラを起動する手順について述べる。
【０１０７】
図７〜図１３は、周辺デバイスからＣＰＵへの割り込み制御(１〜７)の説明図であり、縦軸をシミュレーション時刻とした割り込みタイミングを示している。
【０１０８】
図７は、ＣＰＵのmainスレッドが周辺デバイスを起動し、割り込み待ちになるまで制御の流れを示している。以下、その手順を述べる。
(1)  ＣＰＵのmainスレッドによる周辺デバイスの起動
ＣＰＵのmainスレッドの記述例を以下に示す。
void  cpu::main(void)｛
bus->write（address,data,C_TID）;  //周辺デバイススレッドを起動
intct1->no_wait_intreq()；    //周辺デバイスからの割り込み要求待ち
tik[C_TID]->sum_time(cT1)；
tik[C_TID]->sum_time(cT2)；
tik[C_TID]->sum_time(cTK)；
}
【０１０９】
上記のＣＰＵのmainスレッドは、bus->writeメソッド呼び出しの手段等により、バス経由の周辺デバイスアクセスで周辺デバイスのスレッドを起動する。この後、ＣＰＵのmainスレッドは割り込み要求を待つために割り込みコントローラintct1に対してintct1->no_wait_intreqメソッド呼び出しを行う。
【０１１０】
このno_wait_intreqメソッドは、周辺デバイスからの割り込み要求を待つことなく、ＣＰＵ動作と周辺デバイス動作を並行して動作させるような場合に、周辺デバイスの起動直後に呼び出すためのメソッドである。
【０１１１】
このno_wait_intreqメソッドは、下記の記述例のように、ＣＰＵが割り込みの発生を待たずに周辺デバイスドライバと並行して動作することを意味するNO_WAIT_INTをcpu_wait_int変数に設定した後、wait(intreq_start)呼び出しを行って周辺デバイスからの割り込み通知待ちとなる。
void  intct1::no_wait_intreq(void){
cpu_wait_int＝NO_WAIT_INT;
wait(intreq_start)；
}
【０１１２】
これに対してＣＰＵが割り込み発生まで待つような場合には、割り込みコントローラintct1に対してintct1->wait_intreqメソッド呼び出しを行い、cpu_wait_int変数にWAIT_INTの値を設定する。wait_intreqメソッドの記述例を下記に示す。
void  intct1::wait_intreq(void){
cpu_wait_int＝WAIT_INT;
wait(intreq_start)；
}
【０１１３】
cpu_wait_intへ設定する値のデータタイプwait_int_tの定義は、例えば以下のように与える。
typedef  enum  {NOJAIT_INT＝O  //  no  wait  for  interrupt  request
,WAIT_INT＝1    //  wait  for  interrupt  request
}wait_int_t;
cpu_wait_int変数は、割り込み要求処理スレッドint_requestで参照される。
【０１１４】
(2)  周辺デバイススレッドからの割り込み要求の通知
周辺デバイスpdevは、ＣＰＵからのwriteメソッドによって起動された後、必要に応じてシミュレーション時刻を進める処理を行い、このＣＰＵに対する割り込みを通知する必要が生じた際、割り込みコントローラintct1に対して割り込み通知を行う。
【０１１５】
周辺デバイスpdevのスレーブ動作の記述例を示す。
void  pdev::write(1ong  address,1ong  data,tid_t  tid){
tik[tid]->sum_time(Tacc)；
addressで指定されるレジスタにdataの書き込みを行う；
if(上記書き込みによって周辺デバイスが起動される場合){
tik[P_TID]->sync_time(tik[tid]->current_time())；
notify(pdev_start)；
}
}
【０１１６】
起動された周辺デバイスpdevにおけるwriteメソッドは、tik[P_TID]->sync_time(tik[tid]->current_time)メソッド呼び出しによって周辺デバイスのシミュレーション時刻をＣＰＵのシミュレーション時刻に設定した後、notify(pdev_start)メソッド呼び出しにより、下記に示す周辺デバイスのmainスレッドを起動する。
void  pdev::main(){
for(;;){      //以下の処理を繰り返す
wait(pdev_start)；//notify(pdev_start)が実行されるまで待つ
tik[PJID]->sum_time(pT1)；//ptikのシミュレーション時刻にpT1経過時間を加算
tik[PJID]->sum_time(pT2)；//ptikのシミュレーション時刻にpT2経過時間を加算
tik[PJID]->sum_time(pTL)；//ptikのシミュレーション時刻にpTL経過時間を加算
//以下の手順によって割り込み要求をＣＰＵに通知する。
tik[I_TID]->sync_time(tik[P_TID]->current_time())；
intct1->intct1_start()；  //割り込み要求を割り込コントローラに通知
tik[P_TID]->flush_time()；
// 制御を割り込コントローラに渡す。
}
}
【０１１７】
起動された周辺デバイスのmainスレッドは、必要に応じてsum_timeメソッド呼び出しによって周辺デバイスのシミュレーション時刻を進め、割り込みをＣＰＵに通知する必要が発生した場合には、割り込みコントローラintct1に対してintct1->intct1_startメソッドを呼び出して、割り込み要求を割り込みコントローラに通知する。
【０１１８】
図８は、周辺デバイスpdevのmainスレッドが割り込みをＣＰＵのmainスレッドに通知し、割り込みハンドラを起動し、ＣＰＵのmainスレッドに制御を渡すまでの制御の流れを示している。以下、その手順を述べる。
【０１１９】
(3)  割り込みコントローラによる割り込み優先度判定
割り込みコントローラintct1におけるintct1_startメソッドは、下記の記述例に示すようにnotify(intct1_start)メソッド呼び出しによって、割り込みコントローラのint_contro1スレッドを起動する。
void  intct1::intct1_start(){
notify(intct1_start)；
}
void  intct1::int_request(){
for(;;){
wait(intct1_start);      //割り込みの発生を待つ
tik[I_TID]->suM_time(iT)；//itikのシミュレーション時刻にiT経過時間を加算割り込み優先度判定を行う。
iｆ（割り込み要求が許可された）{
iｆ(cpu_wait_inｔ==NO_WAIT_INT)
tiｋ[C_TID]->break_time(tik[I_TID]−>current_time()    //  割り込み発生時刻をＣＰＵの中断時刻に設定
,tik[I_TID]->current_sc_time()  //  割り込み発生システム時刻を設定
,&TikIF::flush_time    //flush_timeをＣＰＵの中断メソッドに設定
else
tik[C_TID]=sync_time(tik[I_TID]->current_time();  //
notify(intreq_start);  //
tik[I_TID]->flush_time();  //
notify(inthdr?start);  //
}
}
}
【０１２０】
ここで、I_TIDは割り込みコントローラのタイムキーパー識別子で、下記のように、上述のtid_tにI_TIDを付加することによって定義される。
Typedef  enum{C_TID=0  //Time  Keeper#1=CPU
,P_TID=1  //Time  Keeper#2=Peripheral
,I_TID=2  //Time  Keeper#3=Interrupt  Controller
}tid_t;  //time  keeper  id  type
【０１２１】
上記のように、割り込みコントローラintct1のint_control1スレッドは、wait(intct1_start)によって周辺デバイスからの割り込み要求イベントintct1_startを待っており、周辺デバイスがintct1_startメソッド呼び出しによって、この割り込みの発生待ち状態を解除した場合、周辺デバイスからの割り込み要求の優先度判定を行う。
【０１２２】
この割り込み要求の受付が許可されたならば、この例ではＣＰＵのmainスレッドにおけるno_wait_intメソッド呼び出しによってcpu_wait_intの値はNO_WAIT_INTに設定されるので、ＣＰＵのタイムキーパーctikに対してbreak_timeメソッド呼び出しを行う。このときの引数は、割り込みコントローラの現在のシミュレーション時刻tik[I_TID]->current_time、現在のシステム時刻tik[I_TID]->current_sc_time、及びflush_timeメソッドである。この呼び出しにより、割り込み発生時刻をＣＰＵタイムキーパーの中断時刻として設定し、flush_timeメソッドを中断メソッドとして設定する。
【０１２３】
この後、notify(intreq_start)メソッド呼び出しによってＣＰＵの待ち状態を解除し、flush_timeメソッド呼び出しを行う。これにより、ＣＰＵのmainスレッドに制御が渡される。この後、notify(inthdr_start)呼び出しによって割り込みハンドラを起動する。
【０１２４】
(4)  ＣＰＵのmainスレッドにおける割り込み起動までの処理を継続
上記notify(intreq_start)メソッド呼び出しにより、ＣＰＵのmainスレッドは、intct1->no_wait_intreq()メソッド呼び出しによる周辺デバイスからの割り込み要求待ち状態が解除され、以降に続くsum_timeメソッド呼び出しによってシミュレーション時刻を進める。シミュレーション時刻が、上記break_timeメソッド呼び出しによって設定した中断時刻以上に達した場合、対応する中断メソッド（ＣＰＵタイムキーパーに対するflush_timeメソッド)呼ぴ出しによって、上記notify(inthdr_start)メソッド呼び出しによって起動された割り込みハンドラに制御が渡される。
【０１２５】
(5)  ＣＰＵの割り込みハンドラの実行
下記にＣＰＵの割り込みハンドラinthdrの記述例を示す。
void  cpu::inthdr(){
for(;;){
intct1->wait_inthdr()；    //割り込みコントローラによる割り込み通知待ち
tik[C_TID]->sum_time(hT1)；
tik[C_TID]->sum_time(hT2)；
tik[C_TID]->sum_time(hTM)；
}
}
【０１２６】
割り込みハンドラスレッドintdhrは、割り込みコントローラintct1に対してintct1->wait_inthdrメソッド呼び出しを行う。このwait_inthdrメソッドは、下記の記述例のようにwait(inthdr_start)メソッド呼び出しを行って、周辺デバイスからの割り込み通知待ちとなる。
void  intct1::wait_inthdr(void){
wait(inthdr_start)；
}
【０１２７】
この割り込みハンドラintdhrにおける割り込み待ち状態は、上述の割り込みコントローラintct1における割り込み要求処理スレッドint_requestにおいてnotify(inthdr_start)メソッド呼び出しが行われた時点で解除される。
【０１２８】
起動された割り込みハンドラが実行され、この割り込みハンドラ処理が完了した時点で割り込みハンドラは、再度intct1->wait_inthdrメソッド呼び出しを行って次の割り込み要求待ち状態になる。これにより、ＣＰＵのmainスレッドヘ再度、制御が渡される。
【０１２９】
(6)  ＣＰＵのmainスレッド処理の再開
割り込みハンドラ処理後のmainスレッド処理が再開される。
図９は、ステップ(3)において、break_timeメソッドを実行した際のシミュレーション時刻の様子を示している。
【０１３０】
この図９に示すようにＣＰＵのmainスレッドが周辺デバイスを起動し、この後、ＣＰＵのmainスレッドは周辺デバイスからの割り込み要求が発生するまで、割り込み待ち状態となる。周辺デバイスはsync_timeメソッド呼び出しにより、そのタイムキーパーのシミュレーション時刻をＣＰＵが周辺デバイスを起動した時刻に設定し、以降、sum_time呼び出しによってシミュレーション時刻を進める。
【０１３１】
この際、周辺デバイスがバス経由でメモリなどの他の周辺デバイスをアクセスした場合、flush_timeメソッド呼び出しにより、周辺デバイスのタイムキーパーの積算時間Tsumをゼロクリアすることがある。このflush_timeメソッド呼び出しにより、SystemCシミュレータのシステム時刻が、このタイムキーパーのシミュレーション時刻と一致するように更新される。この周辺デバイスのシステム時刻をbTsysとする。
【０１３２】
周辺デバイスがflush_timeメソッド呼び出した後、sum_timeメソッド呼び出しによってそのタイムキーパーのシミュレーション時刻を進め、そのシミュレーション時刻がbTsimに違したときに、割り込みコントローラに割り込み要求を通知する。
【０１３３】
割り込み要求を割り込みコントローラに通知した時点で、SystemCシミュレータで管理している周辺デバイスのシステム時刻は、flush_timeメソッド呼び出しを実行したときの値bTsysに設定されたままになっているが、タイムキーパーで管理しているシミュレーション時刻はその後のsum_timeメソッド呼び出しによってbTsimに更新されている。
【０１３４】
割り込みコントローラのint_contro1スレッドは、割り込みの通知により起動され、bTsim、bTsys、及び、中断メソッドflush_timeを引数としてbreak_timeメソッド呼び出しを行う。
【０１３５】
ＣＰＵのmainスレッドにおける割り込み待ち状態は、break_timeメソッド呼ぴ出しの直後のnotify(intreq_start)メソッド呼び出しによって解除される。このときのＣＰＵのmainスレッドのSystemCシミュレータのシステム時刻は、notifyメソッド呼び出しを行った周辺デバイスのシステム時刻に設定される。この場合は、待ち状態を解除した周辺デバイスのシステム時刻bTsysの値に設定される。
【０１３６】
これにより、ＣＰＵのタイムキーパーのシミュレーション時刻Tsimは、割り込みコントローラintct1に対して割り込み待ちを行った時刻のままであるが、そのシステム時刻はnotify(intreq_start)メソッド呼び出しによって解除されたシステム時刻bTsysとなり、両時刻が異なっているということになる。
【０１３７】
以上のように、break_timeメソッドにおいて中断時刻待ち行列に中断時刻と中断メソッド以外に中断システム時刻を格納し、sum_timeメソッドにおいて中断時刻待ち行列が空でない場合に中断システム時刻を参照して積算時間を算出するのは、このシミュレーション時刻と中断システム時刻の違いを補正するためである。
【０１３８】
break_timeメソッド呼び出しによって設定した周辺デバイスのシステム時刻をbTsysとした場合、ＣＰＵのmainスレッドにおけるsum_timeメソッド呼び出しにおいては、中断時刻待ち行列が空でないので、積算時間の設定は以下のように行われる。
【０１３９】
ＣＰＵタイムキーパーのシミュレーションTsim時刻が中断システム時刻bTsysよりも小さいとき、Tsimが中断システム時刻bTsysに違していないため、積算時刻Tsumの値をゼロクリアする。
【０１４０】
ＣＰＵタイムキーパーのシミュレーションTsim時刻が中断システム時刻bTsys以上に違したとき、積算時刻Tsumの値をTsim-bTsysの値に設定する。これにより、ＣＰＵタイムキーパーのシミュレーション時刻TsimはSystemCシミュレータのカーネルで管理しているシステム時刻と一致する。
【０１４１】
図１０に示すように、周辺デバイス起動後のＣＰＵのmainスレッドの経過時間をcT1,cT2,…,cTKとし、周辺デバイス起動後の周辺デバイスのmainスレッドの割り込み要求発生までの経過時間をpT1,pT2,…,pTLとし、割り込みコントローラにおける割り込み優先度判定の経過時間をiTとすると、以下の関係が成立する。
(cT1+cT2+…+cTK-1)≦（pT1+pT2+…+PTL）+iT≦(cT1+cT2+…+cTK)
【０１４２】
つまり、ＣＰＵのmainスレッドにおけるtik[C_TID]->sum_time(ctK)メソッド呼び出しを行った際に、ＣＰＵのシミュレーション時刻がそのタイムキーパーに設定した中断時刻(ＣＰＵに対する割り込み通知時刻)を越える場合を示している。ＣＰＵは、mainスレッドにおけるsum_timeメソッド呼び出し後、割り込みハンドラスレッドの実行を開始する。
【０１４３】
なお、上記ステップ(3)の割り込みコントローラの処理では、複数の周辺デバイスからの割り込み要求を受け付けるために、実際にはバスアービタと同様に、割り込み要求の待ち行列管理を行う。下記に割り込みコントローラの詳細な処理を示す。
(3-1)  割り込みコントローラにおいて、割り込み要求と割り込みを要求した周辺デバイスのシミュレーション時刻を割り込み要求待ち行列に格納する。
(3-2)  割り込みを要求した周辺デバイスに対してflush_timeメソッドを実行する。これにより、割り込みを発生する可能性のある他の周辺デバイスヘ制御が渡され、上記(3-1)からの処理が繰り返される。
(3-3)  割り込み要求待ち行列に格納された最も小さいシミュレーション時刻の割り込み要求のうち最も優先度の高い割り込み要求を選択する。
(3-4)  選択した割り込み要求が今回の周辺デバイスからの割り込み要求であるとき、次のステップ(3-5)へ進む。そうでないとき、つまり、他の周辺デバイスの割り込み要求が選択されたとき、周辺デバイスのスレッドを待ち状態にさせる。この待ち状態は、ステップ(3-5)において解除される。待ち状態が解除された後、ステップ(3-3)へ進む。
(3-5)  選択した割り込み要求による割り込みハンドラ処理が起動された時点で、他の割り込み要求の待ち状態をnotifyにより解除する。
【０１４４】
周辺デバイスは、割り込み要求が発生した時点で、割り込みコントローラ経由でＣＰＵのタイムキーパーctikに対してシミュレーション時刻を周辺デバイスのシミュレーション時刻に設定するために、tik[C_TID]->sync_time(tik[P_TID]->current_time())メソッドを呼び出す。この後、ＣＰＵのソフトウェアとして定義されている割り込みハンドラを呼び出す。
【０１４５】
（Ｅ２）割り込み制御(その２)
割り込み制御（その１）の特殊な場合として、ＣＰＵが周辺デバイスのmainスレッドを起動した後、直ちに割り込みハンドラ待ちになる場合がある。このような場合、図１１に示すように、ＣＰＵのmainスレッドにおける周辺デバイスのスレッド起動のためのバスアクセスを行った後、割り込みコントローラintct1に対してintct1->wait_intreqメソッド呼び出しを行い、cpu_wait_int変数にWAIT_INTの値を設定して割り込み要求の発生を待った後、wait(inthdr_end)関数を呼び出して割り込みハンドラの完了待ちとなる。
【０１４６】
このwait(inthdr_end)関数呼び出しによる割り込みハンドラ完了待ち状態は、割り込みハンドラにおける割り込みの受け付け処理が完了した後のnotify(inthdr_end)メソッド呼び出しによって解除される。つまり、ＣＰＵのmainスレッドと割り込みハンドラスレッドを以下の記述例に示すように変更すればよい。
void  CPU:  :main  (void){
bus->write(address,data,C_TID)；//周辺デバイススレッドを起動
intct1->wait_intreq()；        //割り込み要求待ち
wait(inthdr_end)；    //割り込みハンドラの終了待ち
tik[C_TID]->sum_time(cT1)；
tik[C_TID]->sum_time(cT2)；
tik[C_TID]->sum_time(cTK)；
}
void  cpu::inthdr(){
for(;;){
wait(inthdr_start)；
tik[C_TID]->sum_time(hT1)；
tik[C_TID]->sum_time(hT2)；
tik[C_TID]->sum_time(hTM)；
notify(inthdr_end)；    //割り込みハンドラの完了をmainスレッドに通知
}
}
【０１４７】
（Ｅ３）割り込み制御(その３)
上記２つの割り込み制御(その１及びその２)の拡張として、ＣＰＵのmainスレッドが周辺デバイスを起動した後、他の処理(例えば、次に周辺デバイスを起動するための準備)を実行しておき、次に周辺デバイスを起動する直前で、ＣＰＵが周辺デバイスからの割り込み通知があり、割り込みハンドラの実行が完了したかどうかを確認したい場合がある。
【０１４８】
以下にそのような場合のＣＰＵのmainスレッドの記述例を示す。
void  CPU::main(void){
for(i=o;  i<10;  i++){
bus->write(address,data,C_TID)；  //周辺デバイススレッドを起動
intct1->no_wait_intreq()；  //割り込みコントローラによる割り込み通知待ち
tik[C_TID]->sum_time(cT1)；
tik[C_TID]->sum_time(cT2)；
tik[C_TID]->sum_time(cTK)；
if(!inthdr_end_flag)      //既に割り込みハンドラ処理が完了しているとき
wait(inthdr_end)；    //割り込みハンドラの終了待ち
inthdr_end_flag＝false;
}
}
【０１４９】
上の例では、ＣＰＵのmainスレッドはbus->writeメソッドによって周辺デバイススレッドを起動し、その後、経過時間cT1,cT2,…,cTKの順にシミュレーション時刻を進める処理を行った後、wait(inthdr_end)関数呼び出しによって割り込みハンドラの実行完了待ちとなる場合を示している。この場合、割り込みハンドラinthdrの記述例は、以下のようになる。
void  cpu:  :  inthdr  O  {
for(;;){
wait(inthdr_start)；
tik[C_TID]->sum_time(hT1)；
tik[C_TID]->sum_time(hT2)；
tik[C_TID]->sum_time(hTM)；
inthdr_end_flag＝true;
notify(inthdr_end)；    //割り込みハンドラの完了をmainスレッドに通知
}
}
【０１５０】
mainスレッドにおいて、bus->writeメソッドで周辺デバイススレッドを起動した後、intct1->no_wait_intreqメソッド呼び出しによって割り込みコントローラからの割り込み要求を待つのは、割り込み制御(その１)と同様である。
【０１５１】
周辺デバイスからの割り込み要求によってwait(intreq_start)関数呼び出しによる待ち状態が解除されるとＣＰＵのmainスレッドは、経過時間cT1,cT2,…,cTKの順にシミュレーション時刻を進める処理を行った後、wait(inthdr_end)関数呼び出しによって割り込みハンドラの実行完了待ちとなる。
【０１５２】
ＣＰＵのmainスレッドは、tik[C_TID]->sum_time(cTK)メソッド呼び出しにより、経過時間cTKによるシミュレーション時刻を進める処理を行った後、割り込みハンドラ処理が完了したかどうかを調べるために、変数inthdr_end_flagをテストする。
【０１５３】
上記の割り込みハンドラの記述例のように、変数inthdr_end_flagは割り込みハンドラが完了した際にtrueに設定される。この変数がfalseであれば、まだ割り込みハンドラの処理が完了していないことを示しており、wait(inthdr_end)呼び出しを行って割り込みハンドラの完了を待つ。この変数がtrueであれば、既に割り込みハンドラの処理が完了していることを示しており、wait(inthdr_end)をスキップして次の処理に進む。
【０１５４】
（Ｅ４）割り込み制御(その４)
上記の割り込み制御(その１〜その３)では、いずれも割り込みコントローラや割り込みハンドラを独立したスレッドとしてインプリメントしている。このため、割り込みが発生する度にスレッド間のコンテキスト切り替えが発生し、シミュレーション速度が低下する。
【０１５５】
このため、割り込みコントローラや割り込みハンドラをスレッドとしてインプリメントせずに、メソッドとしてインプリメントする方法がある。
【０１５６】
割り込みコントローラにおいて、周辺デバイスからの割り込み要求の判定に要する経過時間iTは、数クロックサイクル程度の小さい値である。従って、割り込みコントローラを独立したスレッドとしてインプリメントしないで、近似的に周辺デバイスのスレッドからメソッドとして呼び出し、割り込み要求の判定に要する経過時間iTを割り込みハンドラ内部でＣＰＵの経過時間として組み込んで近似することも可能である。
【０１５７】
また、割り込みハンドラinthdrは、break_timeメソッドの機能を利用することにより、ＣＰＵタイムキーパーのsum_timeメソッドから呼び出すことが可能である。つまり、割り込みコントローラにおけるbreak_timeメソッドの呼び出しにおいて、ＣＰＵタイムキーパーの中断時刻を割り込み受け付け時刻に設定し、対応するメソッドを割り込みハンドラinthdrに設定する。
【０１５８】
ＣＰＵのmainスレッドにおけるsum_timeメソッド呼び出しにより、ＣＰＵタイムキーパーのシミュレーション時刻が中断時刻(割り込み受け付け時刻)以上に達したことを検出する機能を利用し、割り込みハンドラinthdrをsum_timeメソッドから呼び出すことができる。この場合、割り込みハンドラinthdrや割り込みコントローラint_requestは、スレッドとしてではなく、下記の記述例のようにメソッドとして定義する。
void  cpu::inthdr(){
tik[C_TID]->sum_time(iT)；//ＣＰＵタイムキーパーのシミュレーション時刻に経過時間iTを加算
tik[C_TID]->sum_time(hTI)；
tik[C_TID]->sum_time(hT2)；
tik[C_TID]->sum_time(hTM)；
}
void  intct1::int_request(tid_t  tid){
割り込み優先度判定を行う。
if(割り込み要求が許可された){
if(cpu_wait_int==NOJAIT_INT)
tik[C_TID]->break_time(tik[tid]->current_time()//  割り込み発生時刻をＣＰＵの中断時刻として登録
，tik[tid]->current_sc_time()
，&TikIF::inthdr))；//割り込みハンドラを中断メソッドとして登録
else
tik[C_TID]＝sync_time(tik[I_TID]->current_time())；//割り込み発生時刻をＣＰＵの時刻に設定
notify(intreq_start)；//ＣＰＵの割り込み待ち状態を解除
tik[tid]->flush_time()；//  ＣＰＵのmainスレッドに制御を渡す
}
}
【０１５９】
ここで、&TikIF::inthdrは割り込みハンドラの呼び出しメソッドのアドレスで、例えば、このメソッドをタームキーパー内のメソッドとして以下のように定義する。
void  TikIF::inthdr(){
cpu->inthdr()；
}
【０１６０】
つまり、タイムキーパー内で定義されているinthdrメソッドを中断メソッドとして呼び出した場合、ＣＰＵ内で定義されている割り込みハンドラinthdrが呼び出される。周辺デバイスのmainスレッドは、下記の記述例のように、周辺デバイスのタイムキーパー識別子を引数として上記割り込みコントローラメソッドを呼び出す。
void  pdev::main(){
for(;;){    //以下の処理を繰り返す
wait(pdev_start)；  //notify(pdev_start)が実行されるまで待つ
tik[P_TID]->sum_time(pT1)；//ptikのシミュレーション時刻にpT1経過時間を加算
tik[P_TID]->sum_time(pT2)；//ptikのシミュレーション時刻にpT2経過時間を加算
tik[P_TID]->sum_time(pTL)；//ptikのシミュレーション時刻にpTL経過時間を加算
//以下の手順によって割り込み要求をＣＰＵに通知する。
intct1->int_request(P_TID)；//割り込みコントローラメソッドを呼び出す
}
}
【０１６１】
ＣＰＵのmainスレッドの記述例は、割り込み制御(その１)と同様である。図１２と図１３は、このような制御を行った場合の、割り込み制御(その１)と割り込み制御(その２)に対応する割り込みタイミングを示している。
【０１６２】
以上のように、この実施例１のシミュレータは、current_timeメソッド等の６個のメソッド関数を有しているので、SystemCシミュレータのwait関数を呼び出す回数を削減することが可能になる。これにより、wait関数呼び出しに伴うコンテキスト切り替え制御のオーバーヘッドが減少し、シミュレーション時間を短縮することができるという利点がある。
【実施例２】
【０１６３】
この実施例２は、実施例１のタイムキーパーにおけるsum_timeメソッドの機能を次のように拡張するものである。
【０１６４】
即ち、この実施例２のsum_timeメソッドは、中断要求待ち行列が空でなく、更新したTsimが中断要求待ち行列の先頭に格納された中断時刻以上に達した場合、待ち行列の先頭から順にTsim以下の中断時刻bTsimに対応する中断メソッドmethodを呼び出した後、これらを待ち行列から削除する。この後、シミュレーション時刻Tsimに積算時間Tsumを加算してシミュレーション時刻Tsimを進めると共に、積算時間Tsumに経過時間timeを加算して積算時間Tsumを更新する。
【０１６５】
積算時間Tsumが閾値Tthrを越えた場合、flush_timeメソッド呼び出しを行う。ここで閾値Tthrは、積算時間Tsumの最大値を指定するもので、積算時間Tsumがこの閾値Tthrを越えたときに、flush_timeメソッド呼び出しを行う。これによって、SystemCシミュレータのwait関数が呼び出され、スレッド間のコンテキスト切り替えが行われる。
【０１６６】
つまり、閾値Tthrを適当な値に設定すれば、適当なシミュレーション時間間隔でスレッド間のコンテキスト切り替えが行われ、しかも高速なシミュレーションが実現できる。特殊な場合として、閾値Tthrの値を０に設定した場合、sum_timeメソッドの呼ぴ出しを行う度にflush_timeメソッドが呼び出され、SystemCシミュレータのwait関数が呼ぴ出されるので、実質的にsum_timeメソッド呼び出しを行う代わりにSystemCシミュレータのwait関数呼び出しを呼び出すのと等価になり、sum_timeメソッドの呼び出しを行う度にスレッド間のコンテキスト切り替えが行われる。
【０１６７】
このように、この実施例２のシミュレータは、sum_timeメソッドの機能を拡張することにより、実施例１のシミュレータに比べて高速なシミュレーションが可能になるという利点がある。
【実施例３】
【０１６８】
この実施例３は、実施例１または実施例２のシミュレータに、タイムキーパーを統合するモジュールであるタイムキーパー統合モジュールtiksを追加したものである。
【０１６９】
タイムキーパー統合モジュールtiksに、必要なすべてのタイムキーパーを接続し、各デバイスにタイムキーパー統合モジュールtiksを接続するようにすれば、各デバイスは、これらのタイムキーパーをタイムキーパー統合モジュールtiks経由で参照可能となる。
【０１７０】
このようにタイムキーパー統合モジュールtiksを設け、各デバイスにタイムキーパー統合モジュールtiksを接続することにより、必要なタイムキーパーのメソッド呼び出しが行えるようになる。タイムキーパー統合モジュールtiksの接続は、あたかもクロック同期型シミュレーション・モデルにおけるクロックヘの接続と同様に、タイムキーパーの接続が簡略化される。
【０１７１】
このタイムキーパー統合モジュールtiksは、少なくとも以下のメソッドを有している。
・break_time(tid_t  d_tid,uint64  bTsim,uint64  bTsys,void(TikIF::*method)())メソッド（第７の関数）：タイムキーパー識別子d_tidで指定されるタイムキーパーに対して、break_time(bTsim，bTsys，method)メソッド呼び出しを行う。
・flush_time(tid_t  tid)メソッド（第８の関数）：タイムキーパー識別子tidで指定されるタイムキーパーに対して、flush_time(time)メソッド呼び出しを行う。
・sum_time(tid_t  tid,1ong  time)メソッド（第９の関数）：タイムキーパー識別子tidで指定されるタイムキーパーに対して、sum_time(time)メソッド呼び出しを行う。
・current_time(tid_t  tid)メソッド（第１０の関数）：タイムキーパー識別子tidで指定されるタイムキーパーに対して、current_timeメソッド呼び出しを行い、結果を戻り値として返す。
・sync_time(tid_t  tid,uint64 sTsim)メソッド（第１１の関数）：タイムキーパー識別子tidで指定されるタイムキーパーに対して、sync_time(sTsim)メソッド呼び出しを行う。
【０１７２】
ここで、tidはどのタイムキーパーに対するメソッド呼び出しを行うかを示すタイムキーパー識別子である。下記にこれらのメソッドの記述例を示す。
void  tiks::break_time(tid_td_tid,uint64  bTsim,uint64  bTsys,void(TikIF::*method)()){
tik[(d_tid]->break_time(bTsim,bTsys,method)；
}
void  tiks::flush_time(tid_t  tid){
tik[tid]->flush_time()；
}
void  tiks::sum_time(tid_t  tid,1ong  time){
tik[tid]->sum_time(time)；
}
uint64  tiks::current_time(tid_t  tid){
return  tik[tid]->current_time()；
}
void  tiks::sync_time(tid_t  tid,uint64  sTim){
tik[tid]-〉sync_time(sTim)；
}
【０１７３】
このため、タイムキーパー統合モジュールtiksクラスを、例えば以下のように定義する。
class  tiks
:public  sc_module
,public  tiksIF
{
public:
sc_port＜tikIF，0〉tik;    /*ports  to  CPU  time  keepers  */
void  break_time(tid_t  d_tid,uint64  bTsim,uint64  bTsys,void(TikIF::*method)())；
void  flush_time(tid_t  tid)；
void  sum_time(tid_t  tid,1ong  time)；
uint64  current_time(tid_t  tid)；
void  sync_time(tid_t  tid,uint64  sTsim)；
}
【０１７４】
この機能を利用して下記のようにタイムキーパー統合モジュールtiksへのタイムキーパー接続を行う。
cpu  =  new  cpu(“cpu”)；
pdev  =  new  pdev(“pdev”)；
tdev  =  new  tdev(“tdev”)；
tiks  =  new  tiks(“tiks”)；
ctik  =  new  tik(“ctik”)；
ptik  =  new  tik(“ptik”)；
ttik  =  new  tik(“ttik”)；
cpu->tiks(*tiks)；
pdev->tiks(*tiks)；
tdev->tiks(*tiks)；
tiks->ctik(*ctik)；
tiks->ptik(*ptik)；
tiks-〉ttik(*ttik)；
【０１７５】
このように各スレッドのポートにはタイムキーパー統合モジュールtiksを接続するだけで良く、タイムキーパー接続が簡素化される。以下、各デバイスからのタイムキーパー統合モジュールtiks経由のタイムキーパーのメソッド呼び出しの記述例を示す。
void  CPU::main(void){
tiks->sum_time(C_TID，cT1)；
tiks->sum_time(C_TID，cT2)；
tiks->sum_time(C_TID，cTK)；
}
void  pdev::write  (1ong  address,1ong  data,tid_t  tid){
tiks->sum_time(tid，Tacc)；
addressで指定されるレジスタにdataの書ぎ込みを行う；
if(上記書き込みによって周辺デバイスが起動される場合){
tiks->sync_time(P_TID,tiks->current_time(tid))；
notify(pdev_start)；
}
}
void  pdev::main()  {
for(;;){        //以下の処理を繰り返す
wait(pdev_start)；  //notify(pdev_start)が実行されるまで待つ
tiks->sum_time(P_TID，pTI)；//ptikのシミュレーション時刻にpT1経過時間を加算
tiks->sum_time(P_TID，pT2)；//ptikのシミュレーション時刻にpT2経過時間を加算
tiks->sum_time(P_TID，pTL)；//ptikのシミュレーション時刻にpTL経過時間を加算
}
}
【０１７６】
以上のように、この実施例３のシミュレータは、タイムキーパー統合モジュールtiksを追加したことにより、実施例１及び２のシミュレータに比べてタイムキーパーの接続が簡素化できるという利点がある。
【実施例４】
【０１７７】
この実施例４は、実施例３でflush_timeメソッドの呼び出しを行う代わりに、タイムキーパーで他のデバイスが動作中であることを検出し、他のデバイスが動作中のときにのみ、flush_timeメソッドの呼び出しを行うメソッドを用いるものである。
【０１７８】
このため各タイムキーパーに、少なくともデバイスの状態を示す変数statusを設け、以下のようなメソッドを追加する。
・set_sleepメソッド（第１２の関数）:変数statusを休眠状態SLEEPに設定する関数である。
・set_activeメソッド（第１３の関数）:変数statusを動作状態ACTIVEに設定する関数である。
・get_statusメソッド（第１４の関数）:変数statusを戻り値として返す関数である。
【０１７９】
各デバイスが起動されたとき、そのタイムキーパーtikに対してtik->set_activeソッド呼び出しを行って、デバイスを動作状態に設定する。デバイス動作が終了し、起動待ちになったとき、そのタイムキーパーtikに対してtik->set_sleepソッド呼び出しを行って、デバイスを休眠状態に設定する。任意の時刻において、デバイスの状態を調べたいとき、そのタイムキーパーtikに対してtik->get_statusメソッド呼び出しを行って、デバイス状態を得る。
【０１８０】
前述の周辺デバイスにおけるスレッド起動の記述例を以下に示す。
void  pdev::write(1ong  address,1ong  data,tid_t  tid){
tik[tid]->sum_time(Tacc)；
addressで指定されるレジスタにdataの書き込みを行う；
if(上記書き込みによって周辺デバイスが起動される場合){
tik[P_TID]->sync_time(tik[tid]->current_time())；
tik[P_TID]->set_active()；  //デバイスを動作状態に設定
notify(pdev_start)；
}
}
void  pdev::main(){
for(;;){        //以下の処理を繰り返す
wait(pdev_start)；  //notify(pdev_start)が実行されるまで特つ
tik[P_TID]->sum_time(pT1)；  //ptikのシミュレーション時刻にpT1経過時間を加算
tik[P_TID]->sum_time(pT2)；  //ptikのシミュレーション時刻にpT2経過時間を加算
tik[P_TID]->sum_time(pTL)；  //ptikのシミュレーション時刻にpTL経過時間を加算
//以下の手順によって割り込み要求をＣＰＵに通知する。
tik[I_TID]->sync_time(tik[PJID]->current_time())；
notify(intct1_start)；      //割り込み要求を割り込コントローラに通知
tik[P_TID]->flush_time()；  //制御を割り込コントローラに渡す
tik[P_TID]->set_sleep()；    //デバイスを休眠状態に設定
}
}
【０１８１】
つまり、周辺デバイススレッド起動の前にtik[P_TID]->set_activeメソッド呼び出しによってデバイスを動作状態に設定し、周辺デバイススレッドにおける処理が終了し、次の起動を待つ前にtik[P_TID]->set_sleepメソッド呼び出しによってデバイスを休眠状態に設定する。
【０１８２】
上記のメソッドに加えて、タイムキーパー統合モジュールtiksに、少なくとも以下のメソッドを用意する。
・switch_threads(tid_t
tid)メソッド:タイムキーパー識別子tidで指定されるタイムキーパー以外のデバイスが動作状態である場合に、タイムキーパー統合モジュールtiksに対してflush_time(tid)メソッドの呼び出しを行う。
【０１８３】
他のタイムキーパーのデバイスが動作状態であるか否かは、get_status(tid)==ACTIVEによって判定する。
【０１８４】
下記にこのswitch_threadsメソッドの記述例を示す。
void  tiks::switch_threads(tid_t  tid){
int  i;
for(i=O;  iくtik.size()；i++){
if(tid==i)
continue;
if(tik[i]->get_status==ACTIVE){
tik[tid]->flush_time()；
return;
}
}
}
【０１８５】
ここで、tik.size()は、タイムキーパー統合モジュールtiksのtikポートに接続されているタイムキーパーの数を求めるSystemCシミュレータの関数である。
【０１８６】
上記のように、switch_threadsメソッドは、引数として指定されたタイムキーパー識別子tid以外のtikポートに接続されている全てのタイムキーパーの状態を調べ、いずれからACTIVEであればflush_timeメソッド呼び出しを行いアクティブ状態にあるデバイスに制御を渡す。
【０１８７】
ＣＰＵ、周辺デバイス、及びバス等の各スレッドにおいてflush_timeメソッド呼び出しを行う替わりに、このswitch_threadsメソッド呼び出しを行うことによって、SystemCシミュレータのwait関数呼び出しの回数が削減され、シミュレーション性能が向上する。
【０１８８】
以上のように、この実施例４のシミュレータは、デバイスの状態を示す変数statusとこの変数statusを操作するいくつかのメソッド関数を設けているので、flush_timeメソッドの呼び出しを行う回数が削減され、より高速の動作が可能になるという利点がある。
【０１８９】
なお、本発明は、上記実施例に限定されず、種々の変形が可能である。この変形例としては、例えば、次のようなものがある。
（ａ）  SystemCシミュレータをＣ言語ベースのシミュレータ本体として使用した例を示したが、SpecC等のハードウエアモデル記述用言語によるシミュレータを使用することができる。
（ｂ）  関数や引数の名称は一例である。
（ｃ）  図２〜図１３の動作説明は一例であり、シミュレーション対象のハードウエアやソフトウエアの機能に応じて適宜変更する必要がある。
【図面の簡単な説明】
【０１９０】
【図１】本発明の実施例を示すシミュレータの構成図である。
【図２】ＣＰＵのmainスレッド切り替え制御の説明図である。
【図３】ＣＰＵからの周辺デバイススレッドの起動制御の説明図である。
【図４】ポーリングによるＣＰＵと周辺デバイス間のスレッドの切り替え制御の説明図である。
【図５】バスアービタによるＣＰＵと周辺デバイス間のスレッドの切り替え制御(１)の説明図である。
【図６】バスアービタによるＣＰＵと周辺デバイス間のスレッドの切り替え制御(２)の説明図である。
【図７】周辺デバイスからＣＰＵへの割り込み制御(１)の説明図である。
【図８】周辺デバイスからＣＰＵへの割り込み制御(２)の説明図である。
【図９】周辺デバイスからＣＰＵへの割り込み制御(３)の説明図である。
【図１０】周辺デバイスからＣＰＵへの割り込み制御(４)の説明図である。
【図１１】周辺デバイスからＣＰＵへの割り込み制御(５)の説明図である。
【図１２】周辺デバイスからＣＰＵへの割り込み制御(６)の説明図である。
【図１３】周辺デバイスからＣＰＵへの割り込み制御(７)の説明図である。
【符号の説明】
【０１９１】
１，２    シミュレーション・モデル
１０    シミュレータ
１１    SystemCシミュレータ
１２    タイムキーパー
Ｑ    中断要求待ち行列
Ｘ，Ｙ    変数
current_time,current_sc_time,flush_time,break_time,sum_time,sync_time    メソッド
【図１】
2008059192.tif 000003
【図２】
2008059192.tif 000004
【図３】
2008059192.tif 000005
【図４】
2008059192.tif 000006
【図５】
2008059192.tif 000007
【図６】
2008059192.tif 000008
【図７】
2008059192.tif 000009
【図８】
2008059192.tif 000010
【図９】
2008059192.tif 000011
【図１０】
2008059192.tif 000012
【図１１】
2008059192.tif 000013
【図１２】
2008059192.tif 000014
【図１３】
2008059192.tif 000015