開発サイクルの終盤に見つかる設計不具合は原因の究明とデバッグが極めて困難で、プロジェクトのスケジュール遅れを招きます。重大な設計不具合と思われたものが、検証テストを実行してみると単なるシミュレーション・データの問題であったと判明することも珍しくありません。従来のデバッグ手法は、問題の特定には必ずしも役立っていませんでした。本稿では、プロトコル・アナライザ、波形ビューア、ソースコード・ブラウザを統合したVerdi Transaction Debug Platformで「リアルタイム・シミュレーション・データ」を用いて一般的なUSBプロトコルの問題をデバッグする方法をご紹介します。この方法でデバッグを行うことにより、設計不具合の原因を突き止めるのにかかる時間が大幅に短縮されるなど、多くの利点が得られます。また、信号とソースコードの同期や対話型モードの利用など、Transaction and Protocol Analyzerのその他の利点についてもご紹介します。
ケンブリッジ大学の調査[1]によると、ソフトウェア開発者は約50%の時間をコードのデバッグに費やしており、そのコストは開発者の人件費および間接費に換算すると年間で総額3120億ドルに達しています。インプリメンテーションIP(IIP)デザインのデバッグはそれだけでも非常に複雑なタスクですが、クロス・プロトコルあるいはSoCレベルのデバッグはリアルタイム実行が難しいこと、ターゲット・ソースへの可視性がないこと、そして他のプロトコルへの依存性があることなどの理由により、その難易度は飛躍的に高くなります。このため、どれほど困難なバグでも短時間で解決できる強力なデバッグ・ツールが求められています。従来のツールでこうしたデザインをデバッグするには、まず「printf」を使用した後、ログ・ファイルでメッセージを検索するのが一般的でした。しかしこのような方法は、時間と精度の面で問題があります。本稿では、一般的なUSBプロトコルの問題をいくつか取り上げ、これらをVerdi Transaction Debug Platformで簡単に解決する方法をご説明します。ここでは、従来のアプローチに比べ問題解決の効率がどれだけ向上するのかについて全体像を示すことに主眼を置いているため、あまり複雑な問題については取り上げません。
転送(トランスファー)は1つまたは複数のバス・トランザクションで構成され、トランザクション単位でソフトウェア・クライアントとそのファンクションの間で情報を移動します。つまり、転送を複数のトランザクションに分割してから、USBバス上でデータを送信します。
図1.1:バルクINトランザクションの構造(方向:左から右)
図1.2:バルクOUTトランザクションの構造(方向:左から右)
上述のようにUSB転送は複数のトランザクションに分割されますが、トランザクションは更に複数のパケットに分割されます。このようにいくつもの抽象度にまたがる問題を解決するには、それぞれの転送とパケットの関係を見つける必要があります。ここでは、ホストとデバイスの間で数GBのデータ転送を実行するテスト・ケースにおいて、転送の1つでエラーが発生し、どのパケットでエラーが発生したのかを突き止める場合について考えてみます。これはごく単純な問題ですが、信号FSDBのみに頼ってこの問題を解決しようとすると、非常に長い時間がかかります。ログを使用する場合も、ログ・ファイルのメッセージを取得するには何度もシミュレーションを実行する必要があり、やはり時間がかかります。
Verdi Protocol Analyzerなら、この問題をワンクリックで解決できます(図1.3)。
図1.3:Verdi Protocol Analyzerの画面(グラフ領域は左ほど抽象度が高い)
USBでは、ホスト・ソフトウェアとデバイス上の特定のエンドポイントの間でデータ転送が行われます。各エンドポイントには、デバイスのファンクションの1つが一意に関連付けられます。1つのUSBデバイスは最大31のエンドポイントを持つことができます。エンドポイントの属性(最大パケット・サイズ、バースト・サイズ、方向など)はエンドポイント・ディスクリプタおよびSuperSpeedエンドポイント・コンパニオン・ディスクリプタから読み出すことができます。
エンドポイントには以下の4種類があります。
この問題は、Verdiの検索機能を使用して解決できます。Verdiのツールバーから検索機能を呼び出すと、次のようなダイアログ・ボックスが表示されます。
上図に示したクエリ式を実行すると、エンドポイント0および1のすべてのINおよびOUTトランザクションを見つけることができます。
このクエリを実行すると、一致したオブジェクト/トランザクションが表示されます(図2.2)。
図2.2:Verdi Protocol Analyzerでオブジェクト/トランザクションを検索した結果
トランザクションを選択すると中央部分の表示が同期され、対応する属性がテーブルの[Details]タブに表示されます。
クエリの説明:
(endpoint_number==0 || endpoint_number==1) && xact_type==”IN_TRANSACTION”
xact_type==”OUT_TRANSACTION”
このクエリは属性値を使用して作成しています。Verdi Protocol Analyzerは多くの演算子をサポートしており、複雑なクエリを作成してトランザクションを検索できます。これらのクエリは汎用性が高く、保存して再利用できます。
リンク・コマンドは、リンク・レベルのデータ・インテグリティ、フロー制御、およびリンク・パワー・マネージメントに使用します。リンク・コマンドの長さは8シンボルと決まっており、同じシンボルを繰り返して送信することでエラー耐性を高めています。LGOODは、受信したヘッダ・パケットおよびヘッダ・シーケンス番号にACK(肯定応答)を返すために使用するリンク・コマンドです。LGOODにはシーケンス番号が付きます(Lgood_0~Lgood_7。SSPの場合はLgood_0~Lgood_15)。LCRD_Xはリンク・フロー制御に使用するリンク・コマンドで、4つのインデックスが付きます(LCRD_A、LCRD_B、LCRD_C、LCRD_D)。
この問題も検索機能を使って解決できます。この例では、リンク層トランザクションおよびそれぞれの対応する属性に対してクエリを定義します。VIPはこれらの属性をFSDBでサポートしており、これらを使用してクエリを作成できます。クエリ式の意味は以下のとおりです。
クエリの説明:
(word_info=~”LCRD_A” || word_info=~”LGOOD_7”) && channel==”Rx”
ここでは、対応するリンク層オブジェクトの数値情報を格納する「word_info」属性と結合演算子を使用しています。また、受信したオブジェクトのみを検索対象とするために「channel」属性を使用してオブジェクトにフィルタを適用しています。「channel == ”Tx”」とすると、送信されたオブジェクトが検索対象となります。上記のクエリを実行すると、フィルタ条件を満たすすべてのオブジェクトが検索結果ウィンドウに表示されます(図3.1)。これらのオブジェクトは開始時刻でソートされるため、検索結果を下にスクロールすると、最後のLCRD_AとLGOOD_7をすぐに見つけることができます(図3.1でハイライト表示したオブジェクト)。
図3.1:Verdi Protocol AnalyzerでLCRD_AとLGOOD_7を検索した結果
図4.1:統合型Verdi Transaction Debug Platform
統合型Verdi Transaction Debug Platformでは、複数ツールのすべての機能が1つのプラットフォーム上で同期して動作するため、複雑なシナリオにも対応できます。この統合プラットフォームでは、信号レベル、ソースコード・レベル、または抽象度の高いトランザクション・レベルの可視化によってバグの根本原因を容易に見つけることができます。
USBプロトコルは階層型アーキテクチャで非常に複雑なため、プロトコル階層全体にまたがる問題を単なる信号やログ・メッセージだけを使用してデバッグするのは困難を極めます。しかもパケットはインオーダーで送受信されないため、プロトコルに関する問題を信号レベルだけで特定するのは容易ではありません。シノプシスの検証用IP(VIP)はいずれもVerdi Protocol Analyzerにネイティブに統合され、すべてのパケット/リンク層オブジェクトおよびデバイスが送信してホストが受信したすべての転送/トランザクションに関するそれぞれの意味を可視化できます。
参考文献
[1] Reversible Debugging Software, University of Cambridge, http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.370.9611