AN60486 PSoC® 1 M8C ImageCraft C コード最適化 Archana Yarlagadda 関連プロジェクト: なし 関連製品ファミリ: CY8C2xxxx (すべての PSoC 1 デバイス) ソフトウェア バージョン: PSoC Designer™ 5.4 関連アプリケーション ノート: AN75320、AN60630、AN2017 本アプリケーション ノートについて、ご質問がある場合または支援が必要な場合は、[email protected] までお 問い合わせください。 AN60486 は、PSoC® 1 C コードを最適化して高速化および小型化する方法を説明し、そのコード最適化に役立つ PSoC Designer プロジェクトおよび ImageCraft コンパイラの設定を対象としています。 また、効率的なコーディングのためのガイドライ ンも含みます。 本アプリケーション ノートでは、ユーザーが PSoC 1、PSoC Designer 統合設計環境 (IDE)、C 言語によるプログ ラミングに精通していることを前提とします。PSoC 1 の入門については、「AN75320 - PSoC 1 入門」を参照してください。 目次 はじめに はじめに ............................................................................. 1 PSoC Designer プロジェクトに使用されるフラッシュ (ROM) 容量を削減する方法はいくつかあります。これにより、より小さ い容量の PSoC デバイスを使用することが可能になり、コスト 削減に繋がることがあります。 プロジェクト レベルの最適化................................................ 2 設定 1: 再配置可能なコード開始アドレス ........................ 2 設定 2: コンフィギュレーションの初期化 .......................... 3 設定 3: サブリメーション (Sublimation) とコンデンセーショ ン (Condensation) ......................................................... 4 設定 4: ROM 定数対 RAM 定数 ..................................... 6 ImageCraft Pro コンパイラ オプション .................................. 6 ヒントおよびガイドライン ...................................................... 6 ガイドライン 1: 割り込みサービス ルーチンにおける関数呼 び出しを回避 ................................................................. 6 ガイドライン 2: 算術関数の使用を制限 ........................... 8 ガイドライン 3: 配列インデックス対ポインタ .................... 10 ガイドライン 4: スイッチ文と if-else 文の使用 ................ 11 ガイドライン 5: アセンブラでコードの一部を書く.............. 13 ガイドライン 6: PSoC 1 のビットを操作 .......................... 13 ガイドライン 7: C コードのフラッシュ使用率および実行時間 の計算......................................................................... 14 ImageCraft コンパイラの Standard 版は PSoC Designer と 共に含まれています。より多く最適化を提供する Pro 版を ImageCraft のウェブサイトから購入することもできます。本ア プリケーションノートに付属するコードスニペットは、両方のコン パイラに使用できます。 表示されている例は、Standard 版で コンパイルされました。Pro 版を使用して得られる追加の最適 化についても、本文書で説明されています。 本書で説明する技法を使用するには、PSoC Designer プロジ ェクトの開発およびビルド方法を理解し、C 言語プログラミング の基礎知識を身に付ける必要があります。 PSoC 1 入門は AN75320 を参照して下さい。 PSoC Designer プロジェクトを開発中に、どの程度の ROM スペースを使用しているかを確認するには、図 1 に示されてい るように Output ステータスウィンドウの Build タブをご覧くだ さい。この例で使用されているコード容量は 543 バイトです。 結論 ................................................................................. 15 www.cypress.com 文章番号: 001-82519 Rev. *A 1 ® PSoC 1 M8C ImageCraft C コード最適化 nt 図 1. ROM および RAM 使用量を表示する PSoC Designer ビルド メッセージ Project>Settings を選択して PSoC Designer により、ユー ザー コードの開始アドレスを指定できます。図 3 に示すように ポップアップするウィンドウで、「Linker」を選択します。 図 3. 再配置可能なコード開始アドレスの選択 次のセクションでは、プロジェクト レベルの最適化設定、その 後いくつかのコーディング ガイドラインについて説明します。 プロジェクト レベルの最適化 Project>Settings から、複数の PSoC Designer コード最適 化設定を利用可能です。 設定 1: 再配置可能なコード開始アドレス PSoC Designer プロジェクトがビルドされる際に、ImageCraft コンパイラは C ファイルをアセンブリ ファイルに変換します。 そしてアセンブラがそれらアセンブリ ファイルを再配置可能な オブジェクト ファイルに変換します。 最後に、リンカーが再配 置可能なオブジェクト ファイルを結合し、実行可能な.hex ファ イルを作成します。 テキスト ボックス内に入力するアドレスは、図 4 で示したように、 マップ ファイル (.mp) で見つけられるブート コードのサイズに 基づいています。 図 4. PSoC Designer におけるマップ ファイル ユーザー コードに加えて、.hex ファイルには自動生成された 初期化コード (ブートコード) が含まれています。 続いて、ブー ト コードの拡張を可能にするための一部のフラッシュ バイトを 予約するために機能する、一連の NOP 命令があります。図 2 を参照してください。 ブート コードの直後にコードを強制的に 配置することにより、フラッシュ スペースを節約できます。 図 2. PSoC Designer プロジェクト用のフラッシュ メモリ マップ Start 0x0000 BOOT End NOP NOP Start PROGRAM CODE End www.cypress.com マップ ファイルは、図 5 に示されているように、様々なコード エリアの開始アドレスおよび終了アドレスを表示します。 ブート コードは「TOP」エリアにあり、ご使用のコードは「lit」エリアにあ ります。図 3 の再配置可能なコード開始アドレスを「TOP」エリ アの終了アドレスに設定してフラッシュ スペースを最も効率的 に使用できます。 たとえば、デフォルトの設定は 0x190 (「lit」 エリアの冒頭のアドレス) です。 これを 0x151 (「TOP」エリア の最終のアドレス) に変更すると、ROM にさらに 63 (0x190 – 0x151 = 0x3F) バイトを取得できます。 文章番号: 001-82519 Rev. *A 2 ® PSoC 1 M8C ImageCraft C コード最適化 nt 図 7. コンフィギュレーション初期化の選択 図 5. .mp ファイルにおける「lit」および「TOP」エリア 図 8. 「Loop」と「Direct write」のコードの違い 再配置可能なコード開始アドレスが「TOP」の最終のアドレス よりも低い値に設定されると、エラー メッセージが表示されま す。 たとえば、値を 0x150 に設定し、ブート コードが 0x151 で 終わる場合、図 6 に示すようにエラー メッセージが表示されま す。 図 6. 再配置可能なコード アドレスがブート コードのサイズより も低い場合のエラー 設定 2: コンフィギュレーションの初期化 コード最適化のもう 1 つのオプションは、起動時の PSoC レジ スタの初期化です。図 7 に示すように、レジスタの値は Loop (ループ) または Direct write (直接書き込み) という 2 方式を 使用して設定できます。 これらオプションを使用するには、 Project>Settings を選択し、表示するウィンドウで「Chip Editor」をクリックしてください。 図 8 を見ると、各レジスタ書き込み用のコードが分かるように な り ま す 。 Direct write 方 式 で 使 用 さ れ る コ ー ド (MOV reg[expr]、expr = 3 バイト) は Loop 方式のコード (addr、値 = 2 バイト) より 1 バイト多いです。 しかし、Loop 方式にも 94 バイト使用する表読み出し関数が含まれています。 そのため、 ロードするレジスタが 94 個以上の場合 (これは、最も単純な Designer プロジェクトを除くすべての場合に該当する)、Loop オプションを選択すると使用するフラッシュ容量は少なくなりま す。図 8 に示されているコンフィギュレーション表を使用して初 期化されるレジスタの数は、設計に使用されるリソース (ユー ザー モジュール) の数に依存します。 リソース数を表す値が 大きいほど、多くのレジスタが初期化されます。 そのため、デ ザインにフラッシュ節約のためにユーザー モジュールが多く含 まれており、起動に少しの時間かかってもかまわない場合、 Loop 方式を使用します。 デザインに多くのユーザー モジュ ールを持っていない、またはより高速なデバイスの起動を希望 するなら、Direct write 方式を選択します。 Loop 方式を使用すると、レジスタ アドレスおよび値の表が作 成され、専用関数により表内の値が対応アドレスに書き込ま れます。Direct write 方式を使用すると、レジスタ当たり 1 つ の MOV 命令という形式でレジスタへ直接書き込みます。 選択された方法は、 自動生成されたフ ァイ ル PSOCConfigTBL.asm で符号化されます。 これら 2 方式のコ ードは、図 8 に示されます。 www.cypress.com 文章番号: 001-82519 Rev. *A 3 ® PSoC 1 M8C ImageCraft C コード最適化 nt 設定 3: サブリメーション (Sublimation) とコンデ ンセーション (Condensation) サ ブ リ メ ーシ ョン (sublimation) お よ びコ ンデ ン セ ーシ ョ ン (condensation) は、ImageCraft Standard 版が提供する圧縮 技術です。図 9 に示されているように Project>Settings を 選択し、ポップアップ ウィンドウで「Compiler」をクリックするこ とで設定を行うことができます。 すべてのユーザー モジュール API の全関数がプロジェクトで 使用されている場合、図 12 に示されているように、「no dead symbol found (デッド シンボルが見つかりませんでした)」とい うメッセージが表示されます。 図 12. 「no dead symbol found」メッセージが表示される サブリメーション 図 9. サブリメーション (sublimation) とコンデンセーション (condensation) のオプション コンデンセーション (Condensation) サブリメーション (Sublimation) 「Sublimation」オプションを選択する場合、コンパイラがユー ザー モジュール API (インターフェース コード) における未使 用の関数を削除し、それによりスペースを節約します。 たとえば、プロジェクトに PGA および PWM ユーザー モジ ュールを設置し、両方のユーザー モジュールに「Start」関 数のみを呼び出すことができます。図 10 および図 11 に示 されているように、これらのユーザー モジュール API にお いて不使用の関数を排除することにより 142 バイトのフラッ シュ容量を節約できます。 図 10. サブリメーションを使用しない場合の ROM 使用状況 Condensation オプションを選択する場合、プロジェクトで繰り 返されるコードのセグメント用に関数が形成され、そのコードの 各インスタンスが関数呼び出しに置き換えられます。コード 1 に示されている簡単な例では、プロジェクトの様々な場所で同 じコードが 3 回繰り返されています。 コンデンセーションが有 効にされると、コードの単一インスタンスは関数に変換され、そ のインスタンスが発生するいかなる箇所で、図 13 に示されて いるようにその関数への関数呼び出しに置き換えられます。 そのようなすべての作成された関数は、図 13 に示されている ように、コードの終わりおよび「<created procedures>」ラベル の下に配置されます。 図に示すように、コード 1 用に作成され た関数は「<created procedures>」ラベルで始まります。その ため、インスタンスが使用されるいかなる箇所で、「<created procedures> 」 ラ ベ ル の 呼 び 出 し に 置 き 換 え ら れ ま す 。 「<created procedures>」ラベル下のロケーション「0520」およ び「052B」における関数は、呼び出し可能な関数に変換される、 プロジェクトにおけるその他の重複コードです。 コード 1 /* Instance one */ shadowRegs[PORT_2] |= 0x01; PRT2DR = shadowRegs[PORT_2]; 図 11. サブリメーションを使用する場合の ROM 使用状況 /* Instance two */ shadowRegs[PORT_2] |= 0x01; PRT2DR = shadowRegs[PORT_2]; /* Instance three */ shadowRegs[PORT_2] |= 0x01; PRT2DR = shadowRegs[PORT_2]; www.cypress.com 文章番号: 001-82519 Rev. *A 4 ® PSoC 1 M8C ImageCraft C コード最適化 nt 図 13.「.lst」ファイルにおけるコード 1 のコンデンセーション 図 14. .mp ファイル内の「text」エリア 図 15. 「text」エリアが 256 バイト未満の場合の コンデンセーション 図 16. 重複コードが見つからない場合のコンデンセーション Condensation オプションにより、図 17 に示されているように 相当量の ROM スペースを節約できます。 コードにコンデンセ ーションを適用するには、「text」エリアにおけるコード (図 14 に示している.mp ファイルに見ることができます) が 256 バイト を超える必要があります。 「text」エリアが 256 バイト未満の場 合、「program code in ‘text’ area too small for worthwhile code compression」(「text」エリア内のプログラム コードは、コ ード圧縮には小さ過ぎます) というエラー メッセージが表示さ れます (図 15)。 コンデンセーションを行うための重複コードの インスタンスが見つからない場合、「no worthwhile duplicate found」 (有効な重複が見つかりませんでした) というエラー メ ッセージが表示されます (図 16)。 注 図 15、図 16、図 17 に表示される情報は、コード コンデン セーション中の異なるシナリオをエミュレートするための異なる コードのものです。 www.cypress.com 図 17. コード 1 におけるコンデンセーション (コード 1 は text エ リアが 256 バイトを超える大きいプロジェクトの一部) 注 コンデンセーションが相当量の ROM スペースを減少する が、重複コードを関数呼び出しで置き換えるため、プログラム 実行に遅延を加えます。 文章番号: 001-82519 Rev. *A 5 ® PSoC 1 M8C ImageCraft C コード最適化 nt 設定 4: ROM 定数対 RAM 定数 このオプション (図 9 を参照) は、フラッシュ (ROM) に定数を 置くことで RAM の使用容量を削減しています。フラッシュの使 用量を大幅に削減するわけではありません。 大部分のプロジ ェクトには Treat const as ROM (定数を ROM で扱う) オプシ ョンを選択します。Treat const as RAM (RAM の定数として 扱う) オプションは、主に ImageCraft コンパイラの旧版との下 位互換性のために使用されます。 る小さいループは連続命令へと拡張されるため、ROM の使用 量が増加します。 冗長な割り当てまたは転送命令が削除され るため、ROM の使用が減少します。 ヒントおよびガイドライン ImageCraft Pro コンパイラ オプション いくつかのコーディング技術によりユーザーのファームウェア をより効率的にすることができます。これらの方法は PSoC Designer プロジェクトおよび PSoC 1 で使用可能であ り、また、PSoC 3 および PSoC Creator™などの類似する 8 ビット プロセッサ、IDE およびコンパイラに適用可能です。 ImageCraft Standard コンパイラで提供される最適化オプショ ンに加えて、ImageCraft Pro は図 18 に示されるようにその他 のオプションを提供します。 ガイドライン 1: 割り込みサービス ルーチンにおけ る関数呼び出しを回避 割り込みサービス ルーチン (ISR) の C コードをコンパイルす る場合、ImageCraft コンパイラは ISR が使用する仮想レジス タ (一時値を保存するためにコンパイラが使用するレジスタ) を すべてスタックにプッシュします。 ISR コードに関数呼び出しが 含まれている場合、コンパイラは呼び出された関数により修正 されるレジスタを見分けられません。 ImageCraft C コンパイラ は、最大で 15 の仮想レジスタを使用して一時データをスタック に保存します。 図 18. ImageCraft Pro コンパイラ オプション ImageCraft Standard コンパイラで提供される Sublimation および Condensation オプションは、それぞれ ImageCraft Pro コンパイラの「Eliminate unused user module APIs」 ( 未使用のユーザー モジュール API を削除する) オプションお よび「Enable Code Compression」 (コード圧縮を有効にす る) オプションと同じです。 ImageCraft Pro は、「Eliminate user unused functions」 オプションを提供しています。これは、ユーザーのプロジェクト が巨大でユーザーが使用していない関数を発見することが困 難な場合に非常に役に立ちます。 わかりやすいシナリオはプ ロジェクトがリビジョンを重ねることで、未使用の API がコード に残存し、ROM スペースを消費する傾向があります。 このオ プションが有効にされると、コンパイラは、未使用の API がコ ードに設置されていないこと、そして ROM スペースがその他 の用途に使用可能であることを確認します。 256 バイトを超える RAM を備えた PSoC チップでは、これら 15 の仮想レジスタと共に 4 つのページ ポインタも保存および 復元されます。コード 2 の例では、コンパイラが仮想レジスタを 保存する必要はありません (図 19)。コード 3 に示されている ように関数呼び出しを使用して実装する場合、図 20 に示され ているように、同じ機能でも 15 の仮想レジスタを余計に使用し ます。 各レジスタは、次の追加のオーバーヘッド コードを必要 とします: MOV [2 バイト] + PUSH [1 バイト] + POP [1 バイト] + MOV [2 バイト]で、レジスタごとに合計 6 バイト。コード 3 は、 これらの多くの MOV/PUSH 命令のため、さらに 90 バイトを使 用し、遅延、長期の ISR 実行を必要とします。 コード 2 BYTE bVar1; #pragma interrupt_handler SleepTimerHandler; void SleepTimerHandler(void) { bVar1 = 1; } ImageCraft Pro で 使 用 可 能な も う 1 つのオ プ シ ョ ン は、 「Optimize for speed 」(コードの速度を最適化) です。 この オプションを有効にすると、コードはより高速に実行するように コンパイルされます。 最適化が適用される場所に応じて ROM の使用量が増加、または減少します。 たとえば、コードにおけ www.cypress.com 文章番号: 001-82519 Rev. *A 6 ® PSoC 1 M8C ImageCraft C コード最適化 nt 図 19. 関数呼び出しを伴わない ISR 用に生成されたコード (コード 2) 図 20. 関数呼び出しを伴った ISR 用に生成されたコード (コード 3) コード 3 BYTE bVar1; void TestFunc() { bVar1 = 1; } #pragma interrupt_handler SleepTimerHandler; void SleepTimerHandler(void) { TestFunc(); } www.cypress.com 文章番号: 001-82519 Rev. *A 7 ® PSoC 1 M8C ImageCraft C コード最適化 nt 図 21. コード 4 の ROM 使用量 ガイドライン 2: 算術関数の使用を制限 多くの場合、C コンパイラはインライン アセンブラ コードを使用 して簡単な算術計算を実行します。 しかし、複雑な計算につい ては、代わりに 1 つまたはそれ以上の算術ライブラリ関数をコ ードに追加することがあります。 これは即座には明らかになら ない可能性があります。 処理および変数の種類によりますが、 「+」、「-」、「*」、「/」、「%」、「>」、および「<」のような単純な C 演 算子でさえもライブラリ関数を実行用に必要とすることがありま す。 それらライブラリ関数は極めて効率的で有益ですが、ライブラ リ関数はあなたが予想できない多くのコード スペースを占める ことがあります。 多くの場合、データ型やコード演算子を注意 深く管理することにより、ライブラリ関数の過度の使用を回避 できます。 プログラムが整数演算を使用する場合、使用される変数のサ イズおよび種類 (8、16 または 32 ビット、符号付きまたは符号 なし) に応じて算術ライブラリ関数が追加されます。 様々な関 数のバイト使用量に関する詳細は、Help > Documentation > Designer Specific Documents の下の Libraries User Guide に記載されています。 コード 5 unsigned int iTest1, iTest2; void main(void) { iTest1 = (iTest2 << 1) + iTest2; } 図 22. コード 5 の ROM 使用量 基礎算術関数 (すなわち常に使用されている関数) には、整数 の加算、減算およびシフトが含まれています。 乗算などのそ の他の演算が使用される場合、これらの演算のコードも含ま れます。 乗除算の代わりにシフトおよび加算を使用 冪関数を避ける 符号なし整数の乗除算の代わりにビット シフトおよび加算のよ うな小技を使用することは、コード スペースを節約します。 符 号なし整数では、単一のビット単位のシフト右が 2 による除算 に相当し、シフト左が 2 による乗算に相当します。コード 5 に 示すように、シフトおよび加算を使用することで、乗除算ライブ ラリ関数を含む必要はありません。 冪関数も算術演算ライブラリ関数を追加します。 冪関数を通 分して乗算または除算演算を実行することもできます。例え ば、42= 4×4 です。 前のセクションで説明したように、乗除算 は、シフトおよび加算を使用して実行できます。 そのため、こ れら関数の実装をできる限りシフトおよび加算に換算するこ とにより、限られた量の冪関数を有するプログラムにおいて コードス ペースを節約できます。 同じ結果をもたらす次の 2 つのコードのスニペットでは、図 21 と図 22 に示されているように、コード 4 の実装はコード 5 より も 55 バイト多く使用します。 この違いは、コードに「__mul16」 関数が追加されているためです。 コード 4 unsigned int iTest1, iTest2; void main(void) { iTest1 = iTest2 *3; } 浮動小数点計算の回避 8 ビット プロセッサの浮動小数点演算は、ほぼ常にライブラリ 関数を必要とします。 基礎算術演算実行用の関数に加えて、 四捨五入、正規化および特別な条件の照合のための共用関 数もコードに追加される可能性があります。 浮動小数点ライブ ラリの詳細については、「Arithmetic Libraries User Guide」 (演算ライブラリ ユーザー ガイド) を参照してください。 概算と して参考までに、次の浮動小数点関数に必要なコード スペー スは以下の通りです (「Arithmetic Libraries User Guide 」 (演 算ライブラリ ユーザー ガイド) にも記載されています)。 比較 (*_fpcmp) = 109–125 バイト 加算 (*_fpadd) = 461–478 バイト 減算 (*_fpsub) = 468–485 バイト 乗算 (*_fpmul) = 406–558 バイト www.cypress.com 文章番号: 001-82519 Rev. *A 8 ® PSoC 1 M8C ImageCraft C コード最適化 nt 除算 (*_fpdiv) = 432–449 バイト 図 24. コード 7 の ROM 使用量 浮動小数点算術関数は、整数算術ライブラリをベースとして使 用します。 これは、浮動小数点演算を使用する際は、整数算 術ライブラリも必要となることを意味します。 浮動小数点演算 を使用する代わりに、変数の範囲が既知の場合は、変数をス ケールして整数演算を直接使用することができます。 たとえば、以下の 2 つのコードでは、変数の範囲は小数点以 下第二位までであることが判明しています。 そのため、すべて の浮動小数点数に 100 を掛けると、浮動小数点演算の代わり に整数演算を使用できます。 この例では、図 23 および図 24 に示されているように、整数演算法のコード 7 の使用量は、内 容が同じだが浮動小数点を用いたコード 6 より 761 バイト少 なくなります。 コード 6 int iTest2, iTest3; float fTest1; void main(void) { fTest1 = iTest2 * 2.42; if(fTest1 > 7.5) { iTest3 = 2; } else { iTest3 = 1; } } 図 23. コード 6 の ROM 使用量 計算の代わりにルックアップ テーブルを使用 計算よりもルックアップ テーブル (LUT) を使用したほうが効率 的な場合があります。 速度、正確性およびコード スペースな ど、複数のトレードオフがあります。 アプリケーションの種類に 応じて選択します。 たとえば、AN2017 – PSoC 1 のサーミスタによる温度測定 で 提供されるプロジェクトは、浮動小数点および LUT 法で実装 するオプションを提供しています。 このプロジェクトでは浮動小 数点演算の代わりに、LUT を使用することによりメモリを 4187 バイト (ルックアップ テーブル用の 3779 バイト、浮動小数点方 程式用の 7966 バイト) 節約しますが、精度のトレードオフがあ ります。 データ型の一貫性の維持 変数のデータ型を選択する際は、関数に必要とされる最も小さ いデータ型を選択します。 たとえば、変数の最大値が 256 を 超えない場合は int の代わりに BYTE を選択します。 同様に、 適用可能な場合では、符号付き変数の代わりに符号なし変数 を選択します。 例えば、プログラムのにおいて変数「iTest1」と 「iTest2」が 255 を超えない場合は、コード 4 を検討します。 こ の場合、コード 8 に示すように「unsigned int」の代わりに 「unsigned char」として宣言することができます。 ROM 使用 量は図 25 に示されています。コード 8 はコード 4 よりも 84 バ イト少なく消費します。 コード 8 コード 7 int iTest1, iTest2, iTest3; void main(void) { iTest1 = iTest2 * 242; if(iTest1 > 750) { iTest3 = 2; } else { iTest3 = 1; } } www.cypress.com unsigned char cTest1, cTest2; void main(void) { cTest1 = cTest2 *3; } 文章番号: 001-82519 Rev. *A 9 ® PSoC 1 M8C ImageCraft C コード最適化 nt コード 9 図 25. コード 8 の ROM 使用量 typedef struct { int iData; BYTE bData; }sData; typedef struct { sData myArray[10]; }sArray; sArray myTest; sData* myPtr; 符号付き変数の正および負の範囲が判明した場合、その変数 をずらして正値にし、符号なしの算術関数を使用できます。 同 様に、変数が–10~+10 の範囲内の値を有することが見込ま れる場合、コード 0 が–10 に対応してコード 20 が+10 に対応 するように、値を 10 ずらします。 コード スペースという点で型キャスティングは高価であるため、 使用されるデータ型の一貫性を維持します。 プログラムにお いて型キャスティングの使用が必須の場合、算術ライブラリの コードスペースを節約するために、変数の型をキャスティングし て同じ算術ライブラリを使用します。 void main(void) { myPtr = myTest.myArray; myPtr->iData = 100; } 図 26. コード 9 の ROM 使用量 ガイドライン 3: 配列インデックス対ポインタ 配列インデックス法では、ImageCraft はインデックスを使用し て各アドレスに直接アクセスします。 アドレスは定数のままと なるため、計算は必要ありません。 ポインタ アクセスの場合、 各アクセスは変数であるポインタに基づいています。 したがっ て、コンパイラはアドレスを入手するために、より多くの計算を 実行する必要があります。 アクセス法が繰り返し使用される場合、アクセスの種類の違い がメモリ使用量に大幅な変化をもたらします。 たとえば、以下の 2 つのコード例について検討します。図 26 および図 27 に示されているように、コード 9 はコード 10 より 25 バイト多く使用します。 そのため、使用されるアクセス方法 の種類 (配列インデックス対ポインタ) を注意深く観察すること は、コードの最適化にとって重要です。 アクセスの種類および 変数の種類には数多くのバリエーションがあります。 アドレス が定数である (その場合にはコンパイラがアドレスを直接に置 き換える) ことの確認がキーとなります。 実行中にアドレス計 算が必要な場合、コンパイラはより多くのコード スペースを使 用します。 一般に、「->」演算子はコード スペースという点で高 価です。 www.cypress.com コード 10 typedef struct { int iData; BYTE bData; }sData; typedef struct { sData myArray[10]; }sArray; sArray myTest; sData* myPtr; void main(void) { myTest.myArray[1].iData = 100; } 文章番号: 001-82519 Rev. *A 10 ® PSoC 1 M8C ImageCraft C コード最適化 nt { 図 27. コード 10 の ROM 使用量 bTest2 = 1; break; } case 3: { bTest2 = 2; break; } case 2: { bTest2 = 3; break; } default: { bTest2 = 4; } ガイドライン 4: スイッチ文と if-else 文の使用 条件判断は、スイッチ文または if-else 文のどちらかを使用で きます。 2 文の相違点は、スイッチ文が常に 16 ビットの比較 をするのに対して、if-else 文が変化する型に基づいて比較を 行います。 1 バイトの変数 (BYTE) の場合、ImageCraft コン パイラは、if-else 文を使用することで、スイッチ文と比べてより 効率的なコードを作り出します。 これは、8 ビットの比較が必 要とするコード スペースは 16 ビットの比較より少ないためで す。 } } 図 28. コード 11 の ROM 使用量 スイッチ文は追加で 9 バイト、さらに各ケースにつき 5 バイトを 使用します。 たとえば、コード 11 に示されているようなデフォ ルトの項目を備えた 4 ケースのスイッチ文は、; break; } case 3: { bTest2 = 2; break; } case 2: { bTest2 = 3; break; } default: { bTest2 = 4; } コード 12 } } 図 28 および図 29 に示されるように、同様のコード 12 よりも (9 + 4 × 4) = 25 バイト多く使用します。 コード 11 BYTE bTest1, bTest2; void main(void) { switch(bTest1) { case 4: www.cypress.com BYTE bTest1, bTest2; void main(void) { if(bTest1 == 4) { bTest2=1; } else if(bTest1 == 3) { bTest2 = 2; } else if(bTest1 ==2) { bTest2 = 3; } else { bTest2=4; } } 文章番号: 001-82519 Rev. *A 11 ® PSoC 1 M8C ImageCraft C コード最適化 nt 図 29. コード 12 の ROM 使用量 条件判断が 2 バイト変数 (WORD) 向けである場合、結果的 なコード サイズはいずれの実装においてもほぼ同一です。 www.cypress.com 文章番号: 001-82519 Rev. *A 12 ® PSoC 1 M8C ImageCraft C コード最適化 nt ガイドライン 5: アセンブラでコードの一部を書く ガイドライン 6: PSoC 1 のビットを操作 アセンブラでプログラムを書くことにより、コンパイラの誤解釈 を回避し、完全なユーザー最適化を可能にします。 アセンブラ でプログラム全体を書くことは退屈で煩わしいですが、コードの 一部だけをアセンブリ言語に変換することによりコードのサイ ズやパフォーマンスを最適化できます。コード 11 のように、ア センブリで bTest2 変数への割り当てを伴うコード 13 を検討し ます。図 30 のように、コード 13 の消費量はコード 11 より 12 バイト少なくなります。 PSoC1 では「ビット」変数向けに定義されたデータ型がありま せん。変数のビット/複数ビットを操作するためには、変数の マスクを論理演算子によりまたは変数に直接割り当てて使用 することができます。 マスクは、操作要件によって定数になる 場合があります。 コード 14 とコード 15 は、変数内のビットを 操作する方法を示しています。 コード 13 BYTE bTest1, bTest2, bTest3; void main(void) { BYTE bTest1, bTest2; void main(void) { switch(bTest1) { case 4: { asm("MOV break; } case 3: { asm("MOV break; } case 2: { asm("MOV break; } default: { asm("MOV } } } コード 14 /* To set first, sixth and eighth bit of the variable */ bTest1 = (0xA1); [_bTest2], 0x1"); /* To clear the second and seventh bits the variable */ bTest2 = bTest2 & (0xBD); [_bTest2], 0x2"); /* To invert the second, fifth and eighth bits in the variable */ bTest3 = bTest3 ^ (0x92); the } [_bTest2], 0x3"); [_bTest2], 0x4"); 図 30. コード 13 の ROM 使用量 変数は、複数のビットの定義を有し、1 つ以上のビットが変数 内の他のビットに影響を与えずに操作しなければならない場 合、ビットを操作するために論理演算子を使用します。 これら の操作は、XOR、AND、および OR 命令を使用します。 コー ド 14 に該当する.asm コードは以下のように<プロジェクト名 >.lst ファイル (Workspace>Output Files) に生成されます。 /* To set first, sixth and eighth bit of the variable */ bTest1 = bTest1 | (0xA1); __text_start|_main|_main: 62 D0 00 MOV REG[0xD0],0x0 2E 03 A1 OR [bTest1],0xA1 /* To clear the second and the seventh bits the variable */ bTest2 = bTest2 & (0xBD); 62 D0 00 MOV REG[0xD0],0x0 26 02 BD AND [bTest2],0xBD /* To invert the second, fifth and eighth bits in the variable */ bTest3 = bTest3 ^ (0x92); 62 D0 00 MOV REG[0xD0],0x0 51 04 MOV A,[bTest3] 31 92 XOR A,0x92 53 04 MOV [bTest3],A www.cypress.com 文章番号: 001-82519 Rev. *A 13 ® PSoC 1 M8C ImageCraft C コード最適化 nt address: 8F FF JMP address 注 MOV REG[0xD0],0x0 命 令 は 、 グ ロ ー バ ル 変 数 「bTest1/bTest2/bTest3」の RAM ページ番号をセットします。 変数のサイズが単一のビットであるか、または変数で定義され ているすべてのビットが同時に割り当て/操作されている場合 は、コード15のように、直接割り当てを使用して操作します。 こ の場合、XOR、AND、およびORよりも1サイクル速いMOV命 令を使用します。 注 命令の実行に要するサイクル数を調べるには「Help」>「 Documentation 」 「 Compiler and Programming Documents 」 に あ る Assembly Language User Guide 、 PSoC Designer の付録 A5、「Instruction Set Summary」を 参照してください。 コード15 注 MOV REG[0xD0],0x0 命令は、 「bTest1/bTest2/bTest3」変数の RAM ページ番号を設定しま す。 ガイドライン 7: C コードのフラッシュ使用率および 実行時間の計算 コード メモリ使用量およびプログラム実行時間が関心事であ る場合、関数のフラッシュの使用量やコードとそのコードの実 行時間を知るのは手動による最適化に役立ちます。 関数のコード サイズを調べるには Workspace>Output Files にある<プロジェクト名>.mp というファイルを参照してくだ さい。.mp ファイルは、コード エリアとそのエリアで定義された 関数/定数によってコード メモリの使用状況に関する詳細を 提供します。 また、図 31 に示すように、RAM エリアとそれら のエリアで定義されたグローバル変数のアドレスで、RAM の 使用状況に関する詳細も提供します。 図 31..mp ファイル内のアドレスおよびメモリの詳細 BYTE bTest1, bTest2; void main(void) { /* To clear the first and the second bits and set the third bit of a three bits variable */ bTest1 = 0x04; /* To invert the variable */ bTest2 = ~ (bTest2); } 該当する.asmコードは以下の通りです。 BYTE bTest1, bTest2; void main(void) { /* To clear the first and the second bits and set the third bit of a three bits variable */ bTest1 = 0x04; __text_start|_main|_main: 62 D0 00 MOV REG[0xD0],0x0 55 02 04 MOV [bTest1],0x4 /* To invert the variable */ bTest2 = ~ (bTest2); 62 D0 00 MOV REG[0xD0],0x0 } 51 03 73 53 03 address: MOV A,[bTest2] CPL A MOV [bTest2],A 8F FF JMP address www.cypress.com 注 コード/RAM エリアの詳細については、C 言語コンパイラ ユーザー ガイド、セクション 6.9、、およびアセンブリ言語のユ ーザー ガイド、セクション 5.1 を参照してください。 関数のコード サイズを調べるには、.mp ファイル内の関数名を 検索します。 カスタム エリアで関数を配置していない場合、デ フォルトでは、すべてのユーザー定義関数が「text」コード エリ アに配置されます (図 32)。図 32 では、コード 16 で定義され た「main」、「function1」、および「function2」の開始アドレスを 示しています。 「main」のコード サイズを調べるためには、 「main」のアドレスから以下の関数 (この場合「function1」) の アドレスを引きます。 「main」のサイズは 55 バイト (0x034E – 0x0317 = 0x0037) で、「function1」は 9 バイト (0x0357 – 0x034E = 0x0009)で、「function2」は 9 バイト (0x0360 – 0x0357 = 0x0009)です。 文章番号: 001-82519 Rev. *A 14 ® PSoC 1 M8C ImageCraft C コード最適化 nt コード 16 while (1) { } address: 8X XX int bTest; void main(void) { bTest = ++bTest; } JMP address JMP命令は、実行に5 CPUサイクルかかります。 CPUクロッ クが24MHzであれば、JMP命令の実行時間は以下になります。 void function1(int a) { a++; return; } この速度では、CPUは、約0.208 あたり1 (JMP) 命令を実行 し、つまり1秒あたり(1/0.208) = 480万の命令を実行します。 void function2(int b) { b--; return; } 例 2: 次のように単純な加算の例を検討します。 void main(void) { BYTE bTest1, bTest2; while(1) { bTest1 = bTest1 + bTest2; } } 図 32..mp ファイルを使用したフラッシュ計算 対応.asmコードは以下のとおりです。 コード実行時間を計算するには、個別の命令の実行時間を把 握する必要があります。 個別の命令の実行時間を調べるには Help > Documentation > Compiler and Programming Documents 」 に あ る Assembly Language User Guide 、 PSoC Designer の付録 A5、「Instruction Set Summary」を 参照してください。 表の「CPU クロック サイクル」の欄は、命 令を実行するのに必要な CPU クロック数を提供します。 命令 の実行期間を調べるには、CPU のクロック周期で、その値を 掛けます。 以下の実施例は、異なるコードでの実行時間の計 算を示します。 BYTE bTest1, bTest2; while(1) { bTest1 = bTest1 + bTest2; address1: 52 01 MOV A,[X+1] address2: 05 00 ADD [X+0],A } address3: 8X XX JMP address1 前コードの実行は6 (MOV) + 8 (ADD) + 5 (JMP) = 19ク ロック サイクルかかります。 この場合、平均1命令当たりは 19/3=6.33サイクルです。 CPUクロックが24MHzであれば、 コード全体の実行時間は以下になります。 例 1: 次のように空「while (1)」ループを取り上げます。 このレートでは、CPUは、0.792/3 = 0.264 Sあたり1命令を実行 し、つまり1秒あたり (1/0.264) = 37.9万の命令を実行します。 void main(void) { while (1) { } } 結論 .asm<プロジェクト名>.lst ファイルで生成された「while (1)」ル ープに該当する.asm コードは以下の通りです。 www.cypress.com 上記のガイドラインはコードの最適化に役立ちます。 その中に は、ImageCraft コンパイラ特有のものもあれば、一般的なも のもあります。 ファームウェアの開発中または開発後にこれら 文章番号: 001-82519 Rev. *A 15 ® PSoC 1 M8C ImageCraft C コード最適化 nt の提案に従うことは、コード スペースの最適化に役立ちます。 すべてのコード スニペットおよびスナップショットは、 CY8C28xxx デバイスおよび ImageCraft Standard コンパイ ラ 7.0.5 版についてテストおよびキャプチャされました。その他 の PSoC1 デバイスの場合でも結果が同様でしょう。 これらのガイドラインに加えて、小フラッシュ容量のデバイスを 取り扱っている場合、良い習慣としてはプロジェクトの開発中 にコード サイズの増加を監視することです。 コード スペースが 大幅に増加した場合は常にマップ ファイル (図 4) を検証し、コ ードの最新部分が何らかの予想外の関数を使用しているかを 確認してください。 フラッシュの増加を引き起こすコードの正確 な部分を知ることにより、コードの最適化が簡単になります。 著者について 名前: Archana Yarlagadda 役職: アプリケーション エンジニア 経歴: サイプレスのアプリケーション エンジニ ア、PSoC 担当 ノックスビルのテネシー大学においてアナ ログ VLSI の修士号取得 連絡先: [email protected] コンパイラおよびプロジェクトの最適化オプションの詳細につい て は 、 ImageCraft C Compiler Guide お よ び ImageCraft Assembly Language Guide を参照してください。 www.cypress.com 文章番号: 001-82519 Rev. *A 16 ® PSoC 1 M8C ImageCraft C コード最適化 nt ドキュメントの改版履歴 文書名: PSoC® 1 M8C ImageCraft C コード最適化 – AN60486 文書番号: 001-82519 版 ECN 変更者 発行日 変更内容 ** 3732388 HZEN 09/03/2012 これは英語版 001-60486 Rev. *B からを翻訳した日本語版 001-82519 Rev. **です。 *A 4536599 HZEN 10/13/2014 これは英語版 001-60486 Rev. *E からを翻訳した日本語版 001-82519 Rev. *A です。 www.cypress.com 文章番号: 001-82519 Rev. *A 17 ® PSoC 1 M8C ImageCraft C コード最適化 nt ワールドワイドな販売と設計サポート サイプレスは、事業所、ソリューション センター、メーカー代理店、および販売代理店の世界的なネットワークを保持しています。 お客様 の最寄りのオフィスについては、サイプレスのロケーション ページをご覧ください。 PSoC®ソリューション 製品 車載用 cypress.com/go/automotive psoc.cypress.com/solutions クロック&バッファ cypress.com/go/clocks PSoC 1 | PSoC 3 | PSoC 4 | PSoC 5LP インターフェース cypress.com/go/interface サイプレス開発者コミュニティ 照明 &電源管理 cypress.com/go/powerpsoc cypress.com/go/plc メモリ cypress.com/go/memory PSoC cypress.com/go/psoc タッチ センシング cypress.com/go/touch USB コントローラー cypress.com/go/usb ワイヤレス/RF cypress.com/go/wireless コミュニティ | フォーラム | ブログ | ビデオ | トレーニング テクニカル サポート cypress.com/go/support PSoC は、サイプレス セミコンダクタ社の登録商標です。 PSoC Creator および PSoC Designer は、サイプレス セミコンダクタ社の商標です。 本書で言及するそ の他すべての商標または登録商標は、各社の所有物です。 Cypress Semiconductor 198 Champion Court San Jose, CA 95134-1709 Phone Fax Website : 408-943-2600 : 408-943-4730 : www.cypress.com © Cypress Semiconductor Corporation、2010-2014. 本文書に記載される情報は、予告なく変更される場合があります。 Cypress Semiconductor Corporation (サイプレス セミコンダクタ社) は、サイプレス製品に組み込まれた回路以外のいかなる回路を使用することに対して一切の責任を負いません。 サイプレス セミコ ンダクタ社は、特許またはその他の権利に基づくライセンスを譲渡することも、または含意することもありません。 サイプレス製品は、サイプレスとの書面による合 意に基づくものでない限り、医療、生命維持、救命、重要な管理、または安全の用途のために使用することを保証するものではなく、また使用することを意図したも のでもありません。 さらにサイプレスは、誤動作や故障によって使用者に重大な傷害をもたらすことが合理的に予想される生命維持システムの重要なコンポーネ ントとしてサイプレス製品を使用することを許可していません。 生命維持システムの用途にサイプレス製品を供することは、製造者がそのような使用におけるあら ゆるリスクを負うことを意味し、その結果サイプレスはあらゆる責任を免除されることを意味します。 このソースコード (ソフトウェアおよび/またはファームウェア) はサイプレス セミコンダクタ社 (以下「サイプレス」) が所有し、全世界の特許権保護 (米国およびそ の他の国)、米国の著作権法ならびに国際協定の条項により保護され、かつそれらに従います。 サイプレスが本書面によりライセンシーに付与するライセンスは、 個人的、非独占的かつ譲渡不能のライセンスであり、適用される契約で指定されたサイプレスの集積回路と併用されるライセンシーの製品のみをサポートするカ スタム ソフトウェアおよび/またはカスタム ファームウェアを作成する目的に限って、サイプレスのソースコードの派生著作物をコピー、使用、変更そして作成する ためのライセンス、ならびにサイプレスのソース コードおよび派生著作物をコンパイルするためのライセンスです。 上記で指定された場合を除き、サイプレスの書 面による明示的な許可なくして本ソース コードを複製、変更、変換、コンパイル、または表示することは全て禁止します。 免責条項: サイプレスは、明示的または黙示的を問わず、本資料に関するいかなる種類の保証も行いません。これには、商品性または特定目的への適合性の黙 示的な保証が含まれますが、これに限定されません。 サイプレスは、本文書に記載される資料に対して今後予告なく変更を加える権利を留保します。 サイプレス は、本文書に記載されるいかなる製品または回路を適用または使用したことによって生ずるいかなる責任も負いません。 サイプレスは、誤動作や故障によって使 用者に重大な傷害をもたらすことが合理的に予想される生命維持システムの重要なコンポーネントとしてサイプレス製品を使用することを許可していません。 生 命維持システムの用途にサイプレス製品を供することは、製造者がそのような使用におけるあらゆるリスクを負うことを意味し、その結果サイプレスはあらゆる責 任を免除されることを意味します。 ソフトウェアの使用は、適用されるサイプレス ソフトウェア ライセンス契約によって制限され、かつ制約される場合があります。 www.cypress.com 文章番号: 001-82519 Rev. *A 18