delay count

一個簡易的 delay 迴圈

void delay_count(int count)
{
volatile int i; /* not optimized out */

for(i=0;i<count;i++);
}
編譯結果,需要兩個 register R0, R1,及 4-byte
ff6005b4 <_delay_count>: /* size 0x22 */
ff6005b4: 00 e8 01 00 LINK 0x4; /* (4) */
ff6005b8: 08 30 R1 = R0;
ff6005ba: 00 60 R0 = 0x0 (X); /* R0=0x0( 0) */
ff6005bc: f0 bb [FP -0x4] = R0;
ff6005be: f0 b9 R0 = [FP -0x4];
ff6005c0: 01 09 CC = R1 <= R0;
ff6005c2: 07 18 IF CC JUMP 0xff6005d0 <_delay_count+0x1c>;
ff6005c4: f0 b9 R0 = [FP -0x4];
ff6005c6: 08 64 R0 += 0x1; /* ( 1) */
ff6005c8: f0 bb [FP -0x4] = R0;
ff6005ca: f0 b9 R0 = [FP -0x4];
ff6005cc: 88 08 CC = R0 < R1;
ff6005ce: fb 1f IF CC JUMP 0xff6005c4 <_delay_count+0x10> (BP);
ff6005d0: 01 e8 00 00 UNLINK;
ff6005d4: 10 00 RTS;
如果區域變數 i 沒加 volatile,會被編譯器最佳化,而整個省略成如下。在程式 delay_count() 的呼叫也會被省略。
ff6005b4 <_delay_count>:
ff6005b4: 00 00 NOP;
ff6005b6: 00 00 NOP;
ff6005b8: 00 e8 00 00 LINK 0x0; /* (0) */
ff6005bc: 01 e8 00 00 UNLINK;
ff6005c0: 10 00 RTS;

程式可以作一些調整,節省一些資源
  • 採用 down counter 可直接判斷是否為 0,省用 R1
  • 省略一開始是否為 0 的判斷
  • 不存回
void delay_count(volatile int count)
{
do {
--count;
} while(count);
}
編譯結果 (藍色字是可再節省的部份)
ff6005b4 <_delay_count>: /* size: 0x18 */
ff6005b4: 00 e8 00 00 LINK 0x0; /* (0) */
ff6005b8: b8 b0 [FP + 0x8] = R0;
ff6005ba: b8 a0 R0 = [FP + 0x8];
ff6005bc: f8 67 R0 += -0x1; /* ( -1) */
ff6005be: b8 b0 [FP + 0x8] = R0;
ff6005c0: b8 a0 R0 = [FP + 0x8];
ff6005c2: 00 0c CC = R0 == 0x0;
ff6005c4: fb 17 IF !CC JUMP 0xff6005ba <_delay_count+0x6> (BP);
ff6005c6: 01 e8 00 00 UNLINK;
ff6005ca: 10 00 RTS;
改用組語寫:
void delay_count(int count)
{
asm volatile (
"1:"
"%0 += -0x1;"
"CC = %0 == 0x0;"
"IF !CC JUMP 1b;"
:
:"r"(count)
);
}
編譯結果,橘色字的部份是核心,大小 6 bytes:
ff6005b4 <_delay_count>: /* size 0x14 */
ff6005b4: 00 00 NOP;
ff6005b6: 00 00 NOP;
ff6005b8: 00 e8 00 00 LINK 0x0; /* (0) */
ff6005bc: f8 67 R0 += -0x1; /* ( -1) */
ff6005be: 00 0c CC = R0 == 0x0;
ff6005c0: fe 13 IF !CC JUMP 0xff6005bc <_delay_count+0x8>;
ff6005c2: 01 e8 00 00 UNLINK;
ff6005c6: 10 00 RTS;

有沒有可能進一步改進呢?

1 意見:

jeul 提到...

include/asm-blackfin/delay.h 有一個 __delay() 採用 blackfin 內建的 loop count,每個 loop 是一個 NOP,也就是一個指令週期。