gem5を構成するSimObjectを追加するためのチュートリアルをやってみる。
gem5はSimpleObjectと呼ばれるSimObjectを持っているため、もう一つSimpleObjectを作成すると、コンパイル時に問題が発生する可能性がある。
殆ど多くのgem5はSimObject肩を継承した形で実装されている。SimObjectはメインのインタフェースをすべてのgem5のオブジェクトにエクスポートしている。SimObjectsはPythonスクリプトでアクセス可能なC++のオブジェクトでラップされている。
SimObjectは多くのパラメータを持つことができ、それらはPythonのコンフィグレーションファイルで設定する。整数や浮動小数点数などの単純なパラメータに加えて、他のSimObjectをパラメータとして持つこともできる。これにより、実際のマシンのような複雑なシステム階層を作成することができる。
この章では、簡単な "HelloWorld "SimObjectを作成する。その目的は、SimObjectの作成方法と全てのSimObjectに必要な定型コードを紹介することである。また、SimObjectをインスタンス化する簡単なPython設定スクリプトも作成する。
次のいくつかの章では、この単純なSimObjectを発展させ、デバッグサポート、動的イベント、パラメータを追加する。
gitブランチの使用
新しい機能をgem5に追加するときは、新しいgit branchを作成することが基本である。
git checkout -b hello-simobject
Step 1. 新しいSimObjectのPythonクラスを作成する
各SimObjectには、それに関連付けられたPythonクラスがある。このPythonクラスには、Pythonコンフィグレーションファイルから制御できるSimObjectのパラメータが記述されている。この単純なSimObjectの場合、最初はパラメータなしで始めめる。従って、SimObjectの新しいクラスを宣言し、その名前とSimObjectのC++クラスを定義するC++ヘッダーを設定するだけである。
src/learning_gem5/part2
にHelloObject.py
を作成する。gem5リポジトリをクローンした場合、src/learning_gem5/part2
とconfigs/learning_gem5/part2
にこのチュートリアルで説明したファイルが完成しているはずである。このチュートリアルに従うために、これらを削除するか別の場所に移動するとよい。
from m5.params import * from m5.SimObject import SimObject class HelloObject(SimObject): type = 'HelloObject' cxx_header = "learning_gem5/part2/hello_object.hh" cxx_class = "gem5::HelloObject"
型がクラス名と同じである必要はないが、そのようなことが多い。type
はこのPython SimObjectでラップするC++クラスである。特別な場合のみ、type
とクラス名が異なるべきである。
cxx_header
は、type
パラメータとして使用されるクラスの宣言を含むファイルである。ここでもSimObjectの名前を全て小文字とアンダースコアで表記するのが慣例であるが、これはあくまで慣例である。ここには任意のヘッダーファイルを指定できる。
cxx_class
は、新しく作成されるSimObjectがgem5名前空間内で宣言されていることを指定する属性である。gem5コードベースのほとんどのSimObjectはgem5名前空間で宣言されている!
Step 2. C++でSimObjectを実装する
次に、HelloObject
を実装するhello_object.hh
とhello_object.cc
をsrc/learning_gem5/part2/
ディレクトリに作成する必要がある。
C++オブジェクトのヘッダーファイルから始める。慣例として、gem5では全てのヘッダーファイルを#ifndef/#endif
で囲み、ファイル名とディレクトリを記述する。
SimObjectはgem5名前空間内で宣言されるべきである。したがって、名前空間gem5スコープ内でクラスを宣言する。
ファイル内で必要なのは、クラスを宣言することだけである。HelloObject
はSimObjectなので、C++のSimObjectクラスを継承しなければならない。ほとんどの場合、作成したSimObjectの親はSimObjectそのものではなく、SimObjectのサブクラスになる。
SimObjectクラスは多くの仮想関数を規定している。しかし、これらの関数はいずれも純粋な仮想関数ではないので、最も単純な場合、コンストラクタ以外の関数を実装する必要はない。
全てのSimObjectのコンストラクタはパラメータオブジェクトを取ることを前提としている。このパラメータオブジェクトはビルドシステムによって自動的に作成され、上で作成したようなSimObjectのPythonクラスに基づいている。このパラメータタイプの名前は、オブジェクトの名前から自動的に生成される。HelloObject」の場合、パラメータ型の名前は”HelloObjectParams
”となる。
簡単なヘッダー・ファイルに必要なコードを以下に示す。
#ifndef __LEARNING_GEM5_HELLO_OBJECT_HH__ #define __LEARNING_GEM5_HELLO_OBJECT_HH__ #include "params/HelloObject.hh" #include "sim/sim_object.hh" namespace gem5 { class HelloObject : public SimObject { public: HelloObject(const HelloObjectParams &p); }; } // namespace gem5 #endif // __LEARNING_GEM5_HELLO_OBJECT_HH__
次に、.ccファイルには1つだけでなく2つの関数を実装する必要がある。最初の関数は、HelloObject
のコンストラクタである。ここでは単純にパラメータオブジェクトをSimObjectの親に渡して、"Hello world!"と表示する。
通常、gem5でstd::cout
を使うことはない。 代わりにデバッグ・フラグを使うべきだ。次の章では、代わりにデバッグフラグを使うように修正する。しかし、今は単純なので、単にstd::cout
を使うことにする。
#include "learning_gem5/part2/hello_object.hh" #include <iostream> namespace gem5 { HelloObject::HelloObject(const HelloObjectParams ¶ms) : SimObject(params) { std::cout << "Hello World! From a SimObject!" << std::endl; } } // namespace gem5
注意:SimObjectのコンストラクタが以下のシグネチャに従っている場合、
Foo(const FooParams &)
FooParams::create()
メソッドが自動的に定義される。create()
メソッドの目的は、SimObjectコンストラクタを呼び出してSimObjectのインスタンスを返すことである。ほとんどのSimObjectはこのパターンに従っているが、SimObjectがこのパターンに従っていない場合は、gem5のSimObjectドキュメントに手動でcreate()
メソッドを実装するための詳細情報が記載されている。