ソフト遅延ループを再度、再考
「attribute ((optimize(1)))」で、上手くいったと思ったら、ループの回数が8回以下だと、インライン展開されるようだ・・
色々、あーでもない、こーでもないと、色々やったが、どうも駄目で、最後はインラインアセンブラで書き直す事とした。
しかし、gcc におけるインラインアセンブラの書式がイマイチ判っていないので、google 先生に尋ねながら何とか、物になる実装を見つけた。
※以前、最適化でループが無くならないように「asm("nop");」を入れていたが、アセンブラならその必要は無いので1マシンサイクル短くなる。
※ラベルの付け方がよくわからない・・、なので、他と「かぶらない」ように冗長な名称にしてある。
//-----------------------------------------------------------------//
/*!
@brief マイクロ秒単位の待ち @n
あまり正確では無く、速度に関連する設定に依存します。 @n
※キャッシュ有効、最高速度での物理計測によるパラメータ
@param[in] us 待ち時間(マイクロ秒)
*/
//-----------------------------------------------------------------//
static __attribute__((optimize(1))) void micro_second(uint32_t us) noexcept
{
asm("cmp #0, %[us]" : : [us] "r" (us) );
asm("beq.b micro_second_loop0\n\t"
"micro_second_loop1:");
uint32_t lpn = device::clock_profile::DELAY_MS;
asm("micro_second_loop2:\n\t"
"sub #1, %[lpn]" : : [lpn] "r" (lpn));
asm("bne.b micro_second_loop2");
asm("sub #1, %[us]" : : [us] "r" (us));
asm("bne.b micro_second_loop1\n\t"
"micro_second_loop0:");
// while(us > 0) {
// for(uint32_t n = 0; n < device::clock_profile::DELAY_MS; ++n) {
// asm("nop");
// }
// if(device::clock_profile::DELAY_T1) { asm("nop"); }
// --us;
// }
}
アセンブラコード(RX24T 80MHz):
fffc01a0 <__ZN5utils5delay12micro_secondEm>:
fffc01a0: 61 01 cmp #0, r1
fffc01a2: 20 0d beq.b fffc01af <__romdatastart+0xfffffefb>
fffc01a4 <micro_second_loop1>:
fffc01a4: 75 45 14 mov.l #20, r5
fffc01a7 <micro_second_loop2>:
fffc01a7: 60 15 sub #1, r5
fffc01a9: 21 fe bne.b fffc01a7 <__romdatastart+0xfffffef3>
fffc01ab: 60 11 sub #1, r1
fffc01ad: 21 f7 bne.b fffc01a4 <__romdatastart+0xfffffef0>
fffc01af <micro_second_loop0>:
fffc01af: 02 rts
rxprog を更新
ついでに、rxprog を更新して、RX231 をサポートした。
このプロトコルは、RX24T とほぼ同じもので、プログラム/イレースへ推移する為のコマンドが異なるだけだった。
ほぼ、同じコードの一部を修正して、コードをコピペするのは、悪手でしかないが、見直すには時間的余裕が必要なので、後回しとする。
RX24T もそうなのだが、ID コードのプロテクトが無い場合、プログラム/イレースへ推移すると、自動で、フラッシュをイレースする仕組みがあるようだ・・
なので、コードフラッシュのプログラムでは、「イレース動作」をしないで、いきなり書きに行くようにしている。
まとめ
「時間待ち」は、ソフトで行わなくても、RXマイコンなら、必ずある「TMR タイマー」とかを使って、やれば、正確で、今回のような問題は起きないとも思のだが・・・
TMR を使った時間待ちは、今後の課題としたい・・
又、動作クロックの違いで、プログラムの動作条件(高速動作の場合、フラッシュメモリの速度が足枷となりオペコードの読出しに遅延を設けている)が変わり、クロック数ファクターが異なるので、それに対応したい・・
constexpr を使えば、コンパイル時に計算して、定数を計算可能と思う。