Atmel AVR マイクロコントローラ用の C コード ファームウェアを書きたいと思っています。GCC を使用してコンパイルします。また、コンパイラの最適化 (-Os
または-O2
) を有効にしたいと思います。有効にしない理由は見当たらないからです。おそらく、手動でアセンブリを書くよりもずっと速く、より良いアセンブリが生成されるでしょう。
しかし、最適化されていない小さなコードが必要です。関数の実行をしばらく遅らせたいので、時間を無駄にするために何もしないループを書きたいのです。正確である必要はなく、しばらく待つだけです。
/* How can it NOT optimize this, while optimizing other code? */
unsigned char i, j;
j = 0;
while(--j) {
i = 0;
while(--i);
}
AVR のメモリ アクセスは非常に遅いため、CPU レジスタに保持する必要がi
あります。j
私は見つけたユーティリティ/遅延.hそしてユーティリティ/delay_basic.hからAVRライブラリほとんどの場合、これらの関数を使用する方が良いアイデアかもしれませんが、この質問は有効かつ興味深いままです。
関連する質問:
ベストアンサー1
私は以下のリンクをたどってこの回答を作成しました。dmckee の回答ただし、回答とは異なるアプローチをとります。
関数属性GCC のドキュメントには次のように記載されています:
noinline
この関数属性は、関数がインライン化の対象とならないようにします。関数に副作用がない場合、関数呼び出しがライブであっても、インライン化以外の最適化によって関数呼び出しが最適化されてしまうことがあります。このような呼び出しが最適化されないようにするには、asm ("");
nop
これは私に興味深いアイデアを与えました...内側のループに命令を追加する代わりに、次のようにそこに空のアセンブリ コードを追加してみました。
unsigned char i, j;
j = 0;
while(--j) {
i = 0;
while(--i)
asm("");
}
そして、うまくいきました! そのループは最適化されておらず、追加のnop
命令は挿入されていません。
さらに、 を使用するとvolatile
、gcc はそれらの変数を RAM に保存し、それらを一時レジスタにコピーするためにldd
とを追加しますstd
。一方、このアプローチでは と は使用されずvolatile
、そのようなオーバーヘッドは生成されません。
アップデート:-ansi
または を使用してコードをコンパイルする場合は、キーワードを に-std
置き換える必要があります。asm
__asm__
GCCドキュメントに記載されている。
さらに__asm__ __volatile__("")
、アセンブリステートメントは、配置した場所で実行する必要があります (つまり、最適化のためにループ外に移動してはなりません)。