[質問の詳細をできる限り詳しく説明したいので、大量のテキストが届きます。]
Cortex-M0 用に手書きの ARM アセンブリ コードを最適化する作業を行っています。私が使用しているボードは、STM32F051R8 コントローラーを搭載した STMicro STM32F0Discovery です。コントローラは 48 MHz で動作しています。
残念ながら、最適化を行っているときにかなり奇妙なサイクル カウントが得られます。
たとえばnop
、コードのループにシングルを追加すると、合計で 2 サイクルが追加されます (2 回ループ)。ただし、これを行うと、約 1800 サイクル余分に追加されます。ここで、エクストラnop
(合計 2nop
秒) を追加すると、サイクル カウントは予想される 4 サイクルだけ増加します。
以下のコード例でも同様の奇妙な結果が得られます。コード例は、上部の抜粋を示しています: c = 25 * a + 5 * b
. 一番下の抜粋はc = 5 * (5 * a + b)
. したがって、必要な が 1 つ少ないため、一番下のほうが高速になるはずmov
です。ただし、これを変更します。
movs r4, #25
muls r3, r4, r3
add r2, r3
ldrb r3, [r6, #RoundStep]
movs r4, #5
muls r3, r4, r3
add r2, r3
これに:
movs r4, #5
muls r3, r4, r3
ldrb r5, [r6, #RoundStep]
add r3, r5
muls r3, r4, r3
add r2, r3
予想される1サイクルだけ速度が上がるのではなく、速度が1000サイクル程度低下します...
サイクルをカウントするには、SysTick カウンターを使用し、最大値からカウントダウンし、オーバーフロー割り込みでオーバーフロー カウンターを増やします。これに使用しているコードは、ARM Web サイトからの抜粋とほぼ同じですが、使用している Cortex-M0 用に書き直されています。私のコードは十分に高速であるため、測定中にオーバーフロー割り込みが発生することはありません。
ここで、カウンターが間違った値を示しているのではないかと考え始めたので、手元にあった TI Stellaris LaunchPad のコードも書きました。これは 80 MHz で動作する Cortex-M4F です。このコードは、特定のピンがハイに保持されているサイクル数を測定します。もちろん、M0 のクロックと M4F のクロックは同期して実行されていないため、報告されたサイクル カウントは少し異なります。これは、測定されたサイクル カウントの非常に低い加重指数平均を取ることで「修正」されます ( avg = 0.995 * avg + 0.005 * curCycles
) と測定を 10000 回繰り返します。
M4F で測定された時間は M0 で測定された時間と同じであるため、「残念ながら」SysTick カウンターは M0 で正常に動作しているようです。
最初は、これらの余分な遅延がパイプラインのストールによって引き起こされたものだと思っていましたが、M0 は単純すぎて、M0 のパイプラインに関する詳細な情報が見つからないため、確認できませんでした。 .
だから、私の質問は:ここで何が起こっているのですか?makeを 1 つ追加するnop
と関数に 1000 サイクル/ループが余分にかかるのに、2 つnop
の s を追加してもサイクル数が 2 だけ増加するのはなぜですか? 命令を削除するとコードの実行速度が遅くなるのはなぜですか?