作者 Sam Wang & River Liang 说明,本文对比8位MCU的位操作在系统升级到M0+内核的MCU后所带来的影响,可以作为客户对升级MCU时,对代码及RAM上资源的评估使用. 一)简单的I/O翻转对比.对比条件:MCU为MC9S08PT与KE02,开发平台CW10.3 1.使用PT的代码如下: if (!PORT_PTAD_PTAD0){ PORT_PTAD_PTAD0=1; }else{ PORT_PTAD_PTAD0=0;} PT的代码编译后占用9个Byte。 000002D4 000004 BRSET 0,PORT_PTAD,PORT_PTAD 000002D7 1000 BSET 0,PORT_PTAD 000002D9 202E BRA *+48 ;abs = 0x0309 000002DB 1100 BCLR 0,PORT_PTAD 2.KE是基于ARM的M0+内核,使用的代码如下 if(GPIOA_PDOR & 0x1) { GPIOA_PCOR = 0x1;} else { GPIOA_PSOR = 0X1;} 编译后结果为 00000706: ldr r3,[pc,#24] 00000708: ldr r2,[r3,#0] 0000070a: movs r3,#1 0000070c: ands r3,r2 0000070e: beq main+0x6c (0x718) ; 0x00000718 00000710: ldr r3,[pc,#12] 00000712: movs r2,#1 00000714: str r2,[r3,#8] 00000716: b main+0x20 (0x6cc) ; 0x000006cc 00000718: ldr r3,[pc,#4] 0000071a: movs r2,#1 0000071c: str r2,[r3,#4] 这段M0+内核的代码编译后占用24个Byte 3.KE系列是Freescale在M0+的基础上加入了位操作引擎BME,用以优化ARM内核的位操作性能,使用BME功能的代码如下 #define PTA0_SET (void) (*((volatile unsigned char *)(0x4C000000+(0<<21)+0xF004))) //?==0 //LAS1 第0位 GPIOA_PSOR地址的A0-A19 #define PTA0_CLR (void)(*((volatile unsigned char *)(0x4C000000+(0<<21)+0xFF008))) //LAS1 第0位 GPIOA_PCOR地址的A0-A19 #define PTA0 *((volatile unsigned char *)(0x50000000+(0<<23)+(0<<19)+0xF000)) //UBFX 第0位 1位 GPIOA_PDOR 地址的A0-A18 if (!(PTA0)) {PTA0_SET; } else {PTA0_CLR;} KE的BME代码编译结果如下: 165 if (!(PTA0)){ 00000998: ldr r3,[pc,#24] 0000099a: ldrb r3,[r3,#0] 0000099c: uxtb r3,r3 0000099e: cmp r3,#0 000009a0: bne RTC_IRQHandler+0x18 (0x9a8); 0x000009a8 166 PTA0_SET; //Using BME 000009a2: ldr r3,[pc,#20] 000009a4: ldrb r3,[r3,#0] 000009a6: b RTC_IRQHandler+0x1c (0x9ac); 0x000009ac 168 PTA0_CLR; //Using FASTER GPIO 000009a8: ldr r3,[pc,#16] 000009aa: ldrb r3,[r3,#0] 代码编译后占用20个Byte 4, CW里面有设置可以优化C编译器,具体路径在Project->Proteries->C/C++ Build->Setting->GCC C Complier->Optimization 优化后共用16个Byte 165 if (!(PTA0)){ 0000091e: ldr r3,[pc,#20] 00000920: ldrb r3,[r3,#0] 00000922: cmp r3,#0 00000924: bne RTC_IRQHandler+0x12 (0x92a); 0x0000092a 166 PTA0_SET; //Using BME 00000926: ldr r3,[pc,#16] 00000928: b RTC_IRQHandler+0x12 (0x92c); 0x0000092c 168 PTA0_CLR; //Using FASTER GPIO 0000092a: ldr r3,[pc,#16] 0000092c: ldrb r3,[r3,#0] 5, 结果 如果单纯靠M0+内核访问寄存器,KE代码的占用空间与PT的比为24:9 如果使用KE的BME功能,代码与PT的比为16:9(使用了BME) 在判断Bit时, KE使用代码与PT的比为8:3 单单设置一个Bit时KE与PT代码占比为4:2 因此在M0+等ARM核上进行位操作,其效率比8位单片机低,使用了BME功能后,可以有效提高位操作的性能。 二)典型变量的位操作. 对比条件:MCU为MC9S08PT与KE02,开发平台CW10.3 测试代码:if (xx&1){ xx&=0xFE; }else{ xx|=1;} 1,设置XX在0 page时,其与上面的I/O翻转结果一样,代码为9个BYTES 2,在KE中,编译结果如下,设置优化前,需要52个Bytes的代码量,26个执行周期. if (xx&1){ 00000a52: ldr r3,[pc,#64] 00000a54: ldrb r3,[r3,#0] 00000a56: uxtb r3,r3 00000a58: mov r2,r3 00000a5a: movs r3,#1 00000a5c: ands r3,r2 00000a5e: uxtb r3,r3 00000a60: cmp r3,#0 00000a62: beq main+0x5a (0xa76) ; 0x00000a76 200 xx&=0xFe; 00000a64: ldr r3,[pc,#44] 00000a66: ldrb r3,[r3,#0] 00000a68: uxtb r3,r3 00000a6a: movs r2,#1 00000a6c: bics r3,r2 00000a6e: uxtb r2,r3 00000a70: ldr r3,[pc,#32] 00000a72: strb r2,[r3,#0] 203 }} 00000a74: b main+0x28 (0xa44) ; 0x00000a44 202 xx|=1; 00000a76: ldr r3,[pc,#28] 00000a78: ldrb r3,[r3,#0] 00000a7a: uxtb r3,r3 00000a7c: movs r2,#1 00000a7e: orrs r3,r2 00000a80: uxtb r2,r3 00000a82: ldr r3,[pc,#16] 00000a84: strb r2,[r3,#0] 203 }} 3, 设置优化后,需要22/20个Bytes的代码量,11/10个执行周期. ldr r3,[pc,#40] 199 if (xx&1){ 0000095e: movs r2,#1 197 xx++; 00000960: ldrb r1,[r3,#0] 00000962: adds r1,#1 00000964: uxtb r1,r1 00000966: strb r1,[r3,#0] 199 if (xx&1){ 00000968: ldrb r1,[r3,#0] 0000096a: tst r1,r2 0000096c: beq main+0x34 (0x974) ; 0x00000974 200 xx&=0xFe; 0000096e: ldrb r1,[r3,#0] 00000970: bics r1,r2 00000972: b main+0x34 (0x978) ; 0x00000978 202 xx|=1; 00000974: ldrb r1,[r3,#0] 00000976: orrs r1,r2 00000978: strb r1,[r3,#0] 0000097a: b main+0x20 (0x960) ; 0x00000960 如果采用以空间换时间的话,其参考代码如下. if (xx==0){ xx=1; }else{ xx=0; } 4, 如考虑中断嵌套的话,还令需要4个Byte代码。 5, 结果 KE使用代码与PT的比为至少为20:9。 在判断Bit时, KE使用代码与PT的比为8:3. 6,使用BYTE替换Bit, 编译结果,设置优化前,需要22个BYTES. 197 if (xx==0){ 000009e8: ldr r3,[pc,#44] 000009ea: ldrb r3,[r3,#0] 000009ec: cmp r3,#0 000009ee: bne main+0x38 (0x9f8) ; 0x000009f8 198 xx=1; 000009f0: ldr r3,[pc,#36] 000009f2: movs r2,#1 000009f4: strb r2,[r3,#0] 000009f6: b main+0x3e (0x9fe) ; 0x000009fe 200 xx=0; 000009f8: ldr r3,[pc,#28] 000009fa: movs r2,#0 000009fc: strb r2,[r3,#0] 7,设置优化后,需要16/14个BYTES的代码量. 197 xx++; 0000095c: ldr r3,[pc,#36] 202 xx=1; 0000095e: movs r1,#1 197 xx++; 00000960: ldrb r0,[r3,#0] 00000962: adds r0,#1 00000964: uxtb r0,r0 00000966: strb r0,[r3,#0] 199 if (xx){ 00000968: ldrb r0,[r3,#0] 0000096a: cmp r0,#0 0000096c: beq main+0x32 (0x972) ; 0x00000972 200 xx=0; 0000096e: strb r2,[r3,#0] 00000970: b main+0x20 (0x960) ; 0x00000960 202 xx=1; 00000972: strb r1,[r3,#0] 00000974: b main+0x20 (0x960) ; 0x00000960 8, 结果 ,在RAM的空间允许的情况下,KE使用代码与PT的比为至少为12:9. 三) 8 bit变量加1 1,在PT中对8 bit变量加1,只需要4个BYTES. 24: XX++; 00000014 450000 LDHX #XX 00000017 7C INC ,X 2,M0+的8 bit变量加1,设置优化前,需要14个BYTES 197 xx++; 00000a44: ldr r3,[pc,#48] 00000a46: ldrb r3,[r3,#0] 00000a48: uxtb r3,r3 00000a4a: adds r3,#1 00000a4c: uxtb r2,r3 00000a4e: ldr r3,[pc,#40] 00000a50: strb r2,[r3,#0] 3,而如果使用优化设置,那么要12个BYTES 197 xx++; 0000095c: ldr r3,[pc,#36] 202 xx=1; 0000095e: movs r1,#1 197 xx++; 00000960: ldrb r0,[r3,#0] 00000962: adds r0,#1 00000964: uxtb r0,r0 00000966: strb r0,[r3,#0] 4, 结果 , 在8 bit变量加1时,KE使用代码与PT的比为至少为12:4,但这是32bitARM内核操作8bit变量都普遍存在效率变低的现象。 四) 16位+8位加法 1, 8 bit 编译结果,需要8个BYTES. 0000008 320000 LDHX xx 0000000B AF01 AIX #1 0000000D 960000 STHX xx 2, M0+ 编译结果,设置优化前,需要10个BYTES. 00000a44: ldr r3,[pc,#44] 00000a46: ldr r3,[r3,#0] 00000a48: adds r2,r3,#1 00000a4a: ldr r3,[pc,#40] 00000a4c: str r2,[r3,#0]. 3, M0+ 编译结果,设置优化后,需要8个BYTES. 0000095c: ldr r3,[pc,#20] 0000095c: ldr r3,[pc,#20] 0000095e: ldr r2,[r3,#0] 00000960: adds r2,#1 00000962: str r2,[r3,#0] 4,结果,M0+在16位加法时能够达到8bit单片机的效率,结果相同. 五)结论 因此用户在移植PT(或其它8 bit MCU)代码到KE02时,要选型时需要充分考虑客户原先代码具体运算情况,理论上存在使用KE后代码变大的情况. 但是使用KE等32bitM0+内核时可以在16bit或以上的乘、加运算时获得更好的效率,占用更小的代码空间和运算时间。 另外KE对GPIO的控制寄存器比PT多了一些功能,可以一次操作多个I/O,是不错的功能.
View full article