|
| 技术交流 | 电路欣赏 | 工控天地 | 数字广电 | 通信技术 | 电源技术 | 测控之家 | EMC技术 | ARM技术 | EDA技术 | PCB技术 | 嵌入式系统 驱动编程 | 集成电路 | 器件替换 | 模拟技术 | 新手园地 | 单 片 机 | DSP技术 | MCU技术 | IC 设计 | IC 产业 | CAN-bus/DeviceNe |
GCCAVR C++散转代码效率之分析 |
|
| 作者:hotpower 栏目:单片机 | |
GCCAVR C++散转代码效率之分析 HotPower@126.com 2005.6.29 于西安大雁塔村队部 从以下三种常用的散转代码反汇编列表及HEX文件中可以看出: 1.if-else-endif代码命令执行相对列表从+00000094~+000000D0不等, 命令执行相对条数从0x09~0x45条指令,即9~69条指令. HEX文件代码优化编译长度为1660字节。 2.SWITCH代码命令执行相对列表从+000000B2~+000000F4不等, 命令执行相对条数从0x27~0x69条指令,即39~105条指令. HEX文件代码优化编译长度为1732字节。 3.函数指针代码命令全部执行相对列表都在+00000081处. 命令执行相对条数恒为0x19条指令,即25条指令. HEX文件代码优化编译长度为1602字节。 所以,在本例中(散转个数为15时),函数指针代码的综合效率是最高的,SWITCH代码效率最差。 当然命令执行相对条数并不代表命令执行的实际周期数,这里有命令跳转的原因所在。 但是可以肯定或断定:当散转个数大于一定数目时,函数指针代码的综合效率肯定是最高的, 当只有几个散转时,用函数指针肯定是吃饱了没事干了。 但有一点可以肯定:函数指针代码的结构是最美的...(不用看的,拿来只需加入事件处理的函数名及代码即可) 这篇“水文”就算是我对www.ouravr.com有位高手对我“招安”---劝不要用函数指针的回复吧... “我说HotPower,你何必要这么做呢。你这么大的车,单片机那个老牛,她拉着,恐怕有点费力吧。 建议不要用函数指针!” 可他的“建议”有依据吗???我虽在“传播非典”,但不想误人子弟!!!看我的帖应该先打些“预防针”。。。 在这里也想送他一句话: "胡整就是硬道理,不整永远拉牛车"。 再次谢谢21IC的各位网友!!! 我此帖的目的就是让人们知道“三个臭皮匠如何熏走诸葛亮”的。。。 实际上用不用不是关键,关键的是会选择性的使用更好的方法和手段。 在菜单程序中,也可应用函数指针以简化和优化程序,至少可以压缩代码长度。 此帖将收录到[HotPower的水潭里]的“非奠应用怪潭”中,有时间的话会继续论证此“零耗时消除键盘抖动” 是如何实现任意键组合编程的,会出些“怪招”的,当然是瞎想出来的,也有“理论依据”的依托。 好了,也累了。就灌到这里吧。有耐心的网友可以继续研究下面的汇编代码。。。反正我看了是头晕。。。 函数指针反汇编列表分析 可以看出: 程序入口: +00000069 Key00()到Key24()全部在+00000081处执行,命令执行相对条数0x0081-0x0069+1=0x0019 263: void KeyObj::KeyCommandExec(unsigned CHAR mode) 264: { +00000069: 01FC MOVW R30,R24 Copy register pair 267: KeyCount &= 0x07;//取键盘序号//使用1602字节(.text),运行正确 +0000006A: 8121 LDD R18,Z+1 Load indirect with displacement +0000006B: 7027 ANDI R18,0x07 Logical AND with immediate +0000006C: 8321 STD Z+1,R18 Store indirect with displacement 268: if (KeyCount <= 4) {//只有5个键,KeyCount>=5为3个短接线. +0000006D: 3025 CPI R18,0x05 Compare with immediate +0000006E: F498 BRCC PC+0x14 Branch if carry cleared 269: func = (PFV)pgm_read_word (&KeyCommandTab[mode][KeyCount]);//取FLASH键盘放事件处理表 +0000006F: 2F86 MOV R24,R22 Copy register +00000070: 2799 CLR R25 Clear Register +00000071: 01FC MOVW R30,R24 Copy register pair +00000072: 0FEE LSL R30 Logical Shift Left +00000073: 1FFF ROL R31 Rotate Left Through Carry +00000074: 0FEE LSL R30 Logical Shift Left +00000075: 1FFF ROL R31 Rotate Left Through Carry +00000076: 0FE8 ADD R30,R24 Add without carry +00000077: 1FF9 ADC R31,R25 Add with carry +00000078: 0FE2 ADD R30,R18 Add without carry +00000079: 1DF1 ADC R31,R1 Add with carry +0000007A: 0FEE LSL R30 Logical Shift Left +0000007B: 1FFF ROL R31 Rotate Left Through Carry +0000007C: 5CE6 SUBI R30,0xC6 Subtract immediate +0000007D: 4FFF SBCI R31,0xFF Subtract immediate with carry +0000007E: 9185 LPM R24,Z+ Load program MEMORY and postincrement +0000007F: 9194 LPM R25,Z Load program MEMORY 270: func();//运行KeyX0()~KeyX4() +00000080: 01FC MOVW R30,R24 Copy register pair ---- No Source -------------- |
| 2楼: | >>参与讨论 |
| 作者: 农民讲习所 于 2005-6-29 18:23:00 发布:
题外话: PFV KeyObj::KeyCommandTab[3][5] PROGMEM = {//键盘放事件处理表 {Key00, Key01, Key02, Key03, Key04}, //键释放事件处理 {Key10, Key11, Key12, Key13, Key14}, //压键事件处理 {Key20, Key21, Key22, Key23, Key24} //长压键事件处理 }; 只能和特定任务绑定在一起,结构不好。采用消息处理结构,可以和所有未来处理绑定,实现一对N。 题外话,不影响本课题,请hotpower继续。 |
|
| 3楼: | >>参与讨论 |
| 作者: hotpower 于 2005-6-29 18:37:00 发布:
谢谢所长大人的指导和教育 说实话我主要是想优化几个字节罢了... 前些时候用M8L和T26L构成TWI/USI多机通讯及LCD菜单时把我搞惨了... 最好是---不是程序编不好,而是如何进行代码复用而将好端端的程序结构打乱才能满足空间的要求... 哈哈,那时没一条程序都需考虑如何节约字节... DDRC |= (1 << KeyCP) | (1 << KeyCLK);//三条指令 就必须:(2条指令) DDRC |= (1 << KeyCP); DDRC |= (1 << KeyCLK); 您说我"背不背"... 实际本帖不是目的,解决了问题我心里就高兴,哪怕不吃不睡... 再次谢谢所长大人的指导和教育,农讲所学员向所长致意!!! |
|
| 4楼: | >>参与讨论 |
| 作者: hotpower 于 2005-6-29 20:37:00 发布:
多维数组对函数指针本身就不太公平 多维数组只能加速if和SWITCH的分检能力,却加深了pgm_read_word计算数组的负担. 如果改为一维函数数组: static PFV KeyCommandTab[15];//必须声明为static!!! PFV KeyObj::KeyCommandTab[15] PROGMEM = {//键盘放事件处理表 Key00, Key01, Key02, Key03, Key04, //键释放事件处理 Key10, Key11, Key12, Key13, Key14, //压键事件处理 Key20, Key21, Key22, Key23, Key24 //长压键事件处理 }; void KeyObj::KeyCommandExec(unsigned CHAR num) { PFV func; func = (PFV)pgm_read_word (&KeyCommandTab[num]);//取FLASH键盘放事件处理表 func();//运行KeyX0()~KeyX4() } 这样对函数指针将提高一点效率,但对if和SWITCH执行最后的Key24()就很难受了... 汇编结果如下: 268: func = (PFV)pgm_read_word (&KeyCommandTab[num]);//取FLASH键盘放事件处理表 +00000068: 2FE6 MOV R30,R22 Copy register +00000069: 27FF CLR R31 Clear Register +0000006A: 0FEE LSL R30 Logical Shift Left +0000006B: 1FFF ROL R31 Rotate Left Through Carry +0000006C: 5CE6 SUBI R30,0xC6 Subtract immediate +0000006D: 4FFF SBCI R31,0xFF Subtract immediate with carry +0000006E: 9185 LPM R24,Z+ Load program MEMORY and postincrement +0000006F: 9194 LPM R25,Z Load program MEMORY 269: func();//运行KeyX0()~KeyX4() +00000070: 01FC MOVW R30,R24 Copy register pair ---- No Source ------------------------------------------------------------------------------------ +00000071: 9509 ICALL Indirect call to (Z) +00000072: 9508 RET Subroutine return |
|
| 5楼: | >>参与讨论 |
| 作者: 宇宙飞船 于 2005-6-30 9:02:00 发布:
不用指针的也算高手?庆幸的是已经被 hotpower降级作低手了! JAVA 我末用过,但据我所知 JAVA 就不能用指针,所有的东西只能用大数组,以速度换取稳定性,(注:这个稳定性是相对的,只是有些用C和C++ 的编程人员的习惯和熟练程度问题造成的)。 C和C++ 的精华就是指针,C++更扩充了类,把一切大自然的现象表达在程序设计当中。。。。 |
|
| 6楼: | >>参与讨论 |
| 作者: 51avr 于 2005-6-30 9:25:00 发布:
我的LCD菜单中使用程序指针,感觉比较简洁。支持楼主。 |
|
| 7楼: | >>参与讨论 |
| 作者: pheavecn 于 2005-6-30 13:14:00 发布:
用ICALL指令既占用寄存器,又慢。我一般用堆栈的方式散转。 ;用堆栈的散转程序。 ;16/17个时钟周期(16-bit PC为16),9条指令空间 ;入口为EntryNo。 SubXXX: lds al,EntryNo ;17clocks,9ins andi al,0x7 ;边界检查 subi al,low(-(Branch_Table)) PUSH al ldi al,0 sbci al,high(-(Branch_Table)) PUSH al ret Branch_Table: rjmp Branch0 rjmp Branch1 rjmp Branch2 rjmp Branch3 rjmp Branch4 rjmp Branch5 rjmp Branch6 rjmp Branch7 Branch0: rjmp Sub_End Branch1: rjmp Sub_End Branch2: rjmp Sub_End Branch3: rjmp Sub_End Branch4: rjmp Sub_End Branch5: rjmp Sub_End Branch6: rjmp Sub_End Branch7: rjmp Sub_End Sub_End: ret 看来编译器还不够聪明。 * - 本贴最后修改时间:2005-6-30 13:23:47 修改者:pheavecn |
|
| 8楼: | >>参与讨论 |
| 作者: hotpower 于 2005-6-30 13:24:00 发布:
哈哈...二教主.C++能用ICALL已算做"极品"了 肯定汇编可以打遍天下无敌手,用C++就将就点吧... AVR我可是"极品的菜鸟"---连汇编都不会而直接用C++(而且拒绝用C) 三月"出徒"乱搞了几个"产品". |
|
| 9楼: | >>参与讨论 |
| 作者: pheavecn 于 2005-6-30 13:26:00 发布:
不管执行速度还是占ROM/Register空间,这种散转都好很多。 至于占用的2byte 堆栈... AVR最不缺的就是这个了。 |
|
| 10楼: | >>参与讨论 |
| 作者: hotpower 于 2005-6-30 13:33:00 发布:
51中我喜欢2个PUSH+ret散转 可在"纯情"C或C++中很难实现...光取这个类成员函数指针就让我晕了近3天... 不过icall确实也不错,但要实现2PUSH+ret散转,很难.特别是"拒绝用A"的C人们... 回见...该上班受罪了...羡慕二教主的"自由身"... |
|
| 11楼: | >>参与讨论 |
| 作者: zhousd 于 2005-7-1 8:44:00 发布:
收藏!拿回家慢慢吃。。。 |
|
|
|
| 免费注册为维库电子开发网会员,参与电子工程师社区讨论,点此进入 |
Copyright © 1998-2006 www.dzsc.com 浙ICP证030469号 |