テスト自動化に向けた変数・レジスタのダンプ方法
統合開発環境(IDE)であるIAR Embedded Workbenchは、幅広いマイクロコントローラをサポートします。デバッガであるC-SPYはIDEに含まれており、テスト自動化に便利な多数のマクロ機能を提供します。ここでは変数とレジスタをマクロによってダンプする方法をご紹介します。
C-SPYマクロの構成要素
C-SPYマクロには4つの構成要素があります。
- マクロ関数: 文と変数を含む、一連のマクロで、呼び出すことで文を実行します。マクロ関数は戻り値を持つことができ、また引数を持つこともできます。
- マクロ変数: アプリケーションの外に定義・確保される変数です。マクロ変数はC-SPYの式で使用でき、アプリケーションの変数からの代入も可能です。グローバルなマクロ変数はマクロ関数の外で定義可能で、こうすることでマクロを使用したデバッグセッション中、ずっと存在することが可能です。
- マクロ文字列: 文字列を保持することができる特別なマクロ変数です。C言語の文字列と異なるのは、ターゲットメモリに対するポインタアクセスとはならないことです。さらに、NULLで終端もされていません。組込みマクロ関数である__toString関数はNULLで終端されたC言語の文字列をマクロ文字列に変換することができます。
- マクロ文: C言語の文と同様のふるまいをします。以下の文が使用できます。
- 式
- 条件文
- ループ文
- return文
- ブロック
詳細はC-SPY Debugging Guide(C-SPYデバッグガイド)を参照ください。IAR Embedded WorkbenchのHelp(ヘルプ)メニューから開くことが可能です。
マクロの使用例
下記の例では参考として製品にバンドルされているBasicDebugingプロジェクトを使用します。このプロジェクトはHelp→Information Center→Product explorer→Getting started using IAR Embedded Workbench→Open tutorial workspace(ヘルプ→インフォメーションセンター→サンプルプロジェクト→Getting started using IAR Embedded Workbench→Open tutorial workspace)で開けます。
例1: 変数のログを取る
メモリに割り付けられた変数は全てダンプ可能です。ただし、最適化のレベルによっては、ローカル変数のうち生存区間が短いものはレジスタに割り付けられることがあり、その場合はダンプできません。変数をvolatile宣言することでダンプできるようになります。
Fibonacci.cの20行目にstatic変数callCountの定義があるので、volatileを追加しましょう。
static volatile int_fast8_t callCount;
同ファイルの35行目にローカル変数fibの定義があるので、volatileを追加しましょう。
volatile uint32_t fib;
DoForegroundProcess関数の中で、PutFib(fib)による関数呼び出しを右クリックし、ブレークポイントの切り替え(A)(ログ)を選びましょう。Lと書かれた赤い円が、エディタ上の同じ行の左側に現れます。
同じ行で再度右クリックし、ブレークポイントの編集を選びましょう。そして、C-SPYマクロ”__message”スタイルのチェックボックスをクリックし、有効にしましょう。
次にメッセージの中に以下を記入しましょう。
"callCount: ", callCount:%d, " --- fib: ", fib:%d, "(0x", fib:%x, ")"
最後に条件を条件式の値が変化(H)とし、式はcallCountにしましょう。
Make(メイク)でプロジェクトをビルドし、Download and Debug(ダウンロードしてデバッグ)でデバッグセッションを開始しましょう。
デバッグツールバーからGo(実行)(F5)で実行します。
デバッグログウィンドウが更新されるので確認しましょう。
例2: 変数をファイルにダンプする
File→New File(ファイル→新規ファイル)で新規ファイルを作成し、以下のマクロ関数をコピー&ペーストしましょう。
__var myFileHandle;
// Called once when the debug session starts.
execUserSetup() {
myFileHandle = __openFile("$PROJ_DIR$\\dump.txt", "a");
if (myFileHandle) {
__fmessage myFileHandle, "Logging started...\n";
}
}
dumpValues() {
__var t1, t2;
t1 = callCount;
t2 = fib;
if (myFileHandle) {
__fmessage myFileHandle, "callCount: ", t1:%d, " --- fib: ", t2:%x, "\n";
} else {
__message "ERROR: file dump.txt could not be open.";
return -1;
}
return 0;
}
// Called once when the debug session ends.
execUserExit() {
if (myFileHandle) {
__closeFile(myFileHandle);
}
return 0;
}
コピー&ペーストが終わったら、File→Save as(ファイル→名前を付けて保存)で、dump.macとしてプロジェクトのフォルダ内に保存しましょう。
そのあと、Project→Options→Debugger→Setup macros(プロジェクト→オプション→デバッガ→セットアップマクロ)で、dump.macを使用するマクロファイルとして登録しましょう。
Fibonacci.cに戻り、DoForegroundProcess関数のPutFib(fib)呼び出し箇所を右クリックし、ブレークポイントの切り替え(コード)を選びましょう。
その後、View→Breakpoints(表示→ブレークポイント)でブレークポイントウィンドウを表示し、新しく設定したブレークポイントに対して右クリックでEdit(編集)を選択しましょう。
Action(アクション)に、dumpValues()、と入力しましょう。これによりブレークポイントで停止したときにマクロ関数dumpValuesが実行されます。
再度デバッグを実行すると、デバッグログウィンドウに以下のメッセージが表示され、dump.txtというテキストファイルの中に変数の値がダンプされます。
dump.txtの中身が先ほどデバッグログウィンドウで表示されたものと同じ内容になっていることが確認できます。
例3: レジスタの値をダンプする
下記のマクロ関数dumpRegsをマクロファイルにコピー&ペーストしましょう。このマクロ関数が呼ばれると、レジスタをデバッグログウィンドウに出力します。レジスタはレジスタ名の前に#を付けることで参照できます。
dumpRegs() {
__message "R0, R1, R2, R3 =", #R0:%x, ",", #R1:%x, ",", #R2:%x, ",", #R3:%x;
__message "R4, R5, R6, R7 =", #R4:%x, ",", #R5:%x, ",", #R6:%x, ",", #R7:%x;
__message "R8, R9, R10, R11 =", #R8:%x, ",", #R9:%x, ",", #R10:%x, ",", #R11:%x;
__message "R12, R13, R14, R15 =", #R12:%x, ",", #R13:%x, ",", #R14:%x, ",", #R15:%x;
__message "CPSR =", #CPSR:%x;
}
マクロ関数をデバッグセッション中に手動で実行する
マクロ関数はデバッグセッション中に任意のマクロファイルから実行することが可能です。
View→Quick Watch(表示→クイックウォッチ)でクイックウォッチウィンドウを開きます。
dumpRegs()と入力するとマクロ関数dumpRegsが実行され、デバッグログウィンドウにレジスタの値がダンプされます。
C-SPY実行中は、マクロクイック起動ウィンドウをView→Macro→MacroQuicklaunch(表示→マクロ→マクロクイック起動)で起動できます。
その後、式にdumpRegs()を追加し、青い矢印のアイコンをクリックすることで、マクロ関数dumpRegsを呼び出すことができ、結果はデバッグログウィンドウに表示されます。
まとめ
この記事では、変数やレジスタの値について、C-SPYのマクロ機能でどのようにダンプすることができるか、具体例によって紹介しました。C-SPYのマクロ機能は種々のデバッグとテスト自動化を助けます。複雑なブレークポイントと組み合わせることで、ハードウェア構成や周辺をシミュレーションしたり、デバッグ中にアプリケーションに任意の値を入力したりすることが可能です。