曾经《AVR 高速嵌入式单片机原理及应用》的介绍:代码效率 AVR 46B 对 C51 的112B,
再加上不同数量级上的速度, 让我激动不已.
今天,正好趁将一段 UART 通信的程序移植到 M48 的机会, 对几个编译器做了个简单对比.
keil C 的代码效率特高, 因为我太熟悉它, 对它做了最大优化; 另外也得益于 C51 的
BOOL 处理能力, 因为在我的程序中使用了 8个位变量做状态标志.C51 3B 的判断 2B 的操作和
4B 的位传送, 对 AVR 则 8B, 10B 和 18B! 再加上_testbit_() 的神勇.
不知道 AVR 设计时是如何考虑的, 其实状态位判断在单片机里是很常用的.
ICCAVR 代码压缩 721 words before Code Compression, 650 after. 9% reduction.reduction.
WINAVR 1202 Bytes
TIMERISR
编译器 代码长度 使用寄存器
KEIL C 3EH 62字节 ACC PSW
WINAVR A0~138 98H 152字节 R1 R0 SREG R24 R25
ICCAVR 3A~EA B0H 176字节 R2 R16 R24 R25 SREG
以上地址是从生成的.lss 和 .lis 文件中找到的
UARTISR
KEIL C7.5 16CH 364字节 PSW ACC R0
WINAVR 138~3FC 2C4H 708字节 R1 R0 SREG R18 R19 R20 R22 R23 R24 R25 R30 R31
ICCAVR 0EA~476 38CH 908字节 R0 R2 R3 R4 R5 R16 R18 R24 R25 R30 R31 SREG
去掉状态标志变量的 volatile 修饰后, 代码缩小不少, 特别是 WINAVR .
ICCAVR 代码压缩 705 words before Code Compression, 646 after. 8% reduction.
WINAVR 1110 Bytes
TIMERISR
编译器 代码长度 使用寄存器
KEIL C 3EH 62字节 ACC PSW
WINAVR A0~118 78H 120字节 R1 R0 SREG R24 R25
ICCAVR 3A~E0 A6H 166字节 R2 R16 R24 R25 SREG
UARTISR
KEIL C7.5 16CH 364字节 PSW ACC R0
WINAVR 118~3A0 288H 648字节 R1 R0 SREG R18 R19 R20 R21 R24 R25 R30 R31
ICCAVR 0E0~456 376H 886字节 R0 R2 R3 R4 R5 R16 R18 R24 R25 R30 R31 SREG
winavr 偶然在子程序后面会莫名其妙地生成 2 个 ret
循环优化对比:
WINAVR:
} while(--itemp);
d0: 91 50 subi r25, 0x01 ; 1
d2: e1 f7 brne .-8 ; 0xcc
ICCAVR
006C ; } while(--itemp);
006C 802F mov R24,R16
006E 8150 subi R24,1
0070 082F mov R16,R24
0072 8823 tst R24
0074 C1F7 brne L9
另外, iccavr 有比较累赘的分支跳转, 比如:
0052 2220 tst R2
0054 09F4 brne X0
0056 42C0 rjmp L6 ; 这2条应该可改为 breq L6
0058 X0: ...
对连续位处理的优化:
WINAVR:
102: 97 7f andi r25, 0xF7 ; 247
104: 94 60 ori r25, 0x04 ; 4
106: 90 93 01 01 sts 0x0101, r25
WINAVR 判断出 r25 仍是变量 _busconf 的值, 省去了 lds r25,_busconf 指令
ICCAVR:
00C2 80914600 lds R24,_busconf
00C6 877F andi R24,247
00C8 80934600 sts _busconf,R24
00CC 8460 ori R24,4
00CE 80934600 sts _busconf,R24
如非必要,不要用 volatile 修饰变量, 它会降低优化性能
不过,ICCAVR 完善的 IDE 和 Application Builder 对开发还是有不小帮助的
文章评论(0条评论)
登录后参与讨论