原创 瞎搞就是硬道理(何必讲什么大道理)

2008-2-10 01:29 3514 6 6 分类: MCU/ 嵌入式
瞎搞就是硬道理(何必讲什么大道理)
mood.gif hotpower 发表于 2005-7-1 17:11 AVR 单片机 ←返回版面 按此察看该网友的资料 按此把文章加入收藏夹 按此编辑本帖


瞎搞就是硬道理(何必讲什么大道理)

对testcode的GCC转换为类成员的指针的方法进行了调试及反汇编列表,结果确实不太满意。
虽然运行正常但代码太长,导致我对三种散转的对比报告成为一堆废纸。
使我真的被“梁山好汉”招安入伙,成了第109名“水寇”终于“晚节不保”,心情难以平静。。。
放手一博,瞎搞就是硬道理!!!

先请看类成员的指针的方法的反汇编代码列表:

268:      void KeyObj::KeyCommandExec(unsigned char mode)
269:      {
+00000078:   930F        PUSH    R16              Push register on stack
+00000079:   931F        PUSH    R17              Push register on stack
+0000007A:   93CF        PUSH    R28              Push register on stack
+0000007B:   93DF        PUSH    R29              Push register on stack
+0000007C:   B7CD        IN      R28,0x3D         In from I/O location
+0000007D:   B7DE        IN      R29,0x3E         In from I/O location
+0000007E:   9724        SBIW    R28,0x04         Subtract immediate from word
+0000007F:   B60F        IN      R0,0x3F          In from I/O location
+00000080:   94F8        CLI                      Global Interrupt Disable
+00000081:   BFDE        OUT     0x3E,R29         Out to I/O location
+00000082:   BE0F        OUT     0x3F,R0          Out to I/O location
+00000083:   BFCD        OUT     0x3D,R28         Out to I/O location
+00000084:   018C        MOVW    R16,R24          Copy register pair
277:        KeyCount &= 0x07;//取键盘序号//使用1602字节(.text),运行正确
+00000085:   01FC        MOVW    R30,R24          Copy register pair
+00000086:   8141        LDD     R20,Z+1          Load indirect with displacement
+00000087:   7047        ANDI    R20,0x07         Logical AND with immediate
+00000088:   8341        STD     Z+1,R20          Store indirect with displacement
278:        if (KeyCount <= 4) {//只有5个键,KeyCount>=5为3个短接线.
+00000089:   3045        CPI     R20,0x05         Compare with immediate
+0000008A:   F590        BRCC    PC+0x33          Branch if carry cleared
286:          memcpy_P(&func,  &(KeyObj::KeyCommandTab[mode][KeyCount]), sizeof(PFV));
+0000008B:   2F26        MOV     R18,R22          Copy register
+0000008C:   2733        CLR     R19              Clear Register
+0000008D:   01C9        MOVW    R24,R18          Copy register pair
+0000008E:   0F88        LSL     R24              Logical Shift Left
+0000008F:   1F99        ROL     R25              Rotate Left Through Carry
+00000090:   0F88        LSL     R24              Logical Shift Left
+00000091:   1F99        ROL     R25              Rotate Left Through Carry
+00000092:   0F82        ADD     R24,R18          Add without carry
+00000093:   1F93        ADC     R25,R19          Add with carry
+00000094:   0F84        ADD     R24,R20          Add without carry
+00000095:   1D91        ADC     R25,R1           Add with carry
+00000096:   0F88        LSL     R24              Logical Shift Left
+00000097:   1F99        ROL     R25              Rotate Left Through Carry
+00000098:   0F88        LSL     R24              Logical Shift Left
+00000099:   1F99        ROL     R25              Rotate Left Through Carry
+0000009A:   5C86        SUBI    R24,0xC6         Subtract immediate
+0000009B:   4F9F        SBCI    R25,0xFF         Subtract immediate with carry
+0000009C:   E044        LDI     R20,0x04         Load immediate
+0000009D:   E050        LDI     R21,0x00         Load immediate
+0000009E:   01BC        MOVW    R22,R24          Copy register pair
+0000009F:   01CE        MOVW    R24,R28          Copy register pair
+000000A0:   9601        ADIW    R24,0x01         Add immediate to word
+000000A1:   D317        RCALL   PC+0x0318        Relative call subroutine
287:          (this->*func)();//运行KeyX0()~KeyX4()
+000000A2:   81EB        LDD     R30,Y+3          Load indirect with displacement
---- No Source ------------------------------------------------------------------------------------
+000000A3:   81FC        LDD     R31,Y+4          Load indirect with displacement
+000000A4:   8129        LDD     R18,Y+1          Load indirect with displacement
+000000A5:   813A        LDD     R19,Y+2          Load indirect with displacement
+000000A6:   FFE0        SBRS    R30,0            Skip if bit in register set
+000000A7:   C00B        RJMP    PC+0x000C        Relative jump
+000000A8:   95F5        ASR     R31              Arithmetic shift right
+000000A9:   95E7        ROR     R30              Rotate right through carry
+000000AA:   0FE0        ADD     R30,R16          Add without carry
+000000AB:   1FF1        ADC     R31,R17          Add with carry
+000000AC:   8180        LDD     R24,Z+0          Load indirect with displacement
+000000AD:   8191        LDD     R25,Z+1          Load indirect with displacement
+000000AE:   0F28        ADD     R18,R24          Add without carry
+000000AF:   1F39        ADC     R19,R25          Add with carry
+000000B0:   01F9        MOVW    R30,R18          Copy register pair
+000000B1:   8120        LDD     R18,Z+0          Load indirect with displacement
+000000B2:   8131        LDD     R19,Z+1          Load indirect with displacement
+000000B3:   01FE        MOVW    R30,R28          Copy register pair
+000000B4:   9631        ADIW    R30,0x01         Add immediate to word
+000000B5:   8182        LDD     R24,Z+2          Load indirect with displacement
+000000B6:   8193        LDD     R25,Z+3          Load indirect with displacement
+000000B7:   9595        ASR     R25              Arithmetic shift right
+000000B8:   9587        ROR     R24              Rotate right through carry
+000000B9:   0F80        ADD     R24,R16          Add without carry
+000000BA:   1F91        ADC     R25,R17          Add with carry
+000000BB:   01F9        MOVW    R30,R18          Copy register pair
+000000BC:   9509        ICALL                    Indirect call to (Z)
+000000BD:   9624        ADIW    R28,0x04         Add immediate to word
+000000BE:   B60F        IN      R0,0x3F          In from I/O location
+000000BF:   94F8        CLI                      Global Interrupt Disable
+000000C0:   BFDE        OUT     0x3E,R29         Out to I/O location
+000000C1:   BE0F        OUT     0x3F,R0          Out to I/O location
+000000C2:   BFCD        OUT     0x3D,R28         Out to I/O location
+000000C3:   91DF        POP     R29              Pop register from stack
+000000C4:   91CF        POP     R28              Pop register from stack
+000000C5:   911F        POP     R17              Pop register from stack
+000000C6:   910F        POP     R16              Pop register from stack
+000000C7:   9508        RET                      Subroutine return

在+000000A1处调用以下子程序memcpy_P()执行了4次LPM指令得到跳转地址
+000003B9:   01FB        MOVW    R30,R22          Copy register pair
+000003BA:   01DC        MOVW    R26,R24          Copy register pair
+000003BB:   C002        RJMP    PC+0x0003        Relative jump
+000003BC:   9005        LPM     R0,Z+            Load program memory and postincrement
+000003BD:   920D        ST      X+,R0            Store indirect and postincrement
+000003BE:   5041        SUBI    R20,0x01         Subtract immediate
+000003BF:   4050        SBCI    R21,0x00         Subtract immediate with carry
+000003C0:   F7D8        BRCC    PC-0x04          Branch if carry cleared
+000003C1:   9508        RET                      Subroutine return

可以看出从+0000008B开始到+000003C1结束的代码长度真是吓人呀!!!memcpy_P()真是“厉害”!!!
依此结果必被招安!!!我岂能坐以待毙???

所谓“散转”无非是根据数组的值即函数的地址拿出来用ICALL跳即可,即用“函数指针”跳转。
不管是什么样的“指针”,对于MCU就是两字节的地址!!!在跳转时强制转换成Void(*)()指针不就行了吗???
(KeyObj::*)()那是被“逼良为娼,迫不得已”,不然Key00()等的地址从何而来???请看如何瞎搞???

typedef void (KeyObj::* PFV)(void);//类成员函数指针
typedef void (* PV)(void);//一般函数指针
void KeyObj::KeyCommandExec(unsigned char mode)//类成员函数
{
//
static PFV KeyCommandTab[3][5] PROGMEM = {//键盘放事件处理表
  {&KeyObj::Key00, &KeyObj::Key01, &KeyObj::Key02, &KeyObj::Key03, &KeyObj::Key04}, //键释放事件处理
  {&KeyObj::Key10, &KeyObj::Key11, &KeyObj::Key12, &KeyObj::Key13, &KeyObj::Key14}, //压键事件处理
  {&KeyObj::Key20, &KeyObj::Key21, &KeyObj::Key22, &KeyObj::Key23, &KeyObj::Key24}  //长压键事件处理
};
//
  KeyCount &= 0x07;//取键盘序号//使用1602字节(.text),运行正确
  if (KeyCount <= 4) {//只有5个键,KeyCount>=5为3个短接线.
//  
PV func;//声明一般函数指针
    func = reinterpret_cast<PV>(pgm_read_word(&KeyCommandTab[mode][KeyCount]));//取flash键盘放事件处理表
    func();//运行KeyX0()~KeyX4()
//
/*    
PFV func;//声明类成员函数指针
    memcpy_P(&func,  &(KeyObj::KeyCommandTab[mode][KeyCount]), sizeof(PFV));//取flash键盘放事件处理表
    (this->*func)();//运行KeyX0()~KeyX4()
*/
  }
}

注意:用PFV指针时KeyCommandTab只能做为静态成员数组,它不能在成员函数内定义。而用PV指针两者皆可,代码又小也灵活。

再看此一般函数指针的反汇编代码列表:(和总结报告三种散转对比基本一致,不过多了2条指令但不用静态成员)(如果采用一维数组代码将更简捷)

269:      void KeyObj::KeyCommandExec(unsigned char mode)
270:      {
+00000078:   01FC        MOVW    R30,R24          Copy register pair
278:        KeyCount &= 0x07;//取键盘序号//使用1602字节(.text),运行正确
+00000079:   8121        LDD     R18,Z+1          Load indirect with displacement
+0000007A:   7027        ANDI    R18,0x07         Logical AND with immediate
+0000007B:   8321        STD     Z+1,R18          Store indirect with displacement
279:        if (KeyCount <= 4) {//只有5个键,KeyCount>=5为3个短接线.
+0000007C:   3025        CPI     R18,0x05         Compare with immediate
+0000007D:   F4A8        BRCC    PC+0x16          Branch if carry cleared
282:          func = reinterpret_cast<PV>(pgm_read_word(&KeyCommandTab[mode][KeyCount]));//取flash键盘放事件处理表
+0000007E:   2F86        MOV     R24,R22          Copy register
+0000007F:   2799        CLR     R25              Clear Register
+00000080:   01FC        MOVW    R30,R24          Copy register pair
+00000081:   0FEE        LSL     R30              Logical Shift Left
+00000082:   1FFF        ROL     R31              Rotate Left Through Carry
+00000083:   0FEE        LSL     R30              Logical Shift Left
+00000084:   1FFF        ROL     R31              Rotate Left Through Carry
+00000085:   0FE8        ADD     R30,R24          Add without carry
+00000086:   1FF9        ADC     R31,R25          Add with carry
+00000087:   0FE2        ADD     R30,R18          Add without carry
+00000088:   1DF1        ADC     R31,R1           Add with carry
+00000089:   0FEE        LSL     R30              Logical Shift Left
+0000008A:   1FFF        ROL     R31              Rotate Left Through Carry
+0000008B:   0FEE        LSL     R30              Logical Shift Left
+0000008C:   1FFF        ROL     R31              Rotate Left Through Carry
+0000008D:   5CE6        SUBI    R30,0xC6         Subtract immediate
+0000008E:   4FFF        SBCI    R31,0xFF         Subtract immediate with carry
+0000008F:   9185        LPM     R24,Z+           Load program memory and postincrement
+00000090:   9194        LPM     R25,Z            Load program memory
283:          func();//运行KeyX0()~KeyX4()
+00000091:   01FC        MOVW    R30,R24          Copy register pair
---- No Source ------------------------------------------------------------------------------------
+00000092:   9509        ICALL                    Indirect call to (Z)
+00000093:   9508        RET                      Subroutine return

从以上两个反汇编代码列表中很容易看出后者肯定代码执行效率大大地优于前者。吓搞成功!!!

感谢两位陪我在此“唠叨”,但我们三位可以大声地说“以后再也不怕什么成员数组指针了”。。。

不是像有位网友说的什么“钻研精神”,这是一种“傻劲”,几个“不撞南墙不回头”的“傻帽”。

但“傻人”好象特别有“傻福”,我想做的几乎都得到了“成功”。。。

学习和编程甚至是设计产品等都应该如此,从开始“设计”到最后结果的诞生往往看来都是“幼稚可笑”的,因为结果竟是如此简单。

“坐着的人”往往等结果出来时总是对“站着的人”说---“为什么早点不拿把凳子呢,看你站着累不累???我坐着都看着你累。。。”

那么“坐着的人”为什么不早点站起来帮“站着的人”擦把汗呢???


道理很简单:坐着的人坐习惯了,站着的人累习惯了。坐着的人站起来腰痛,站着的人坐下来腿痛。(相信吗???)

最近在此灌水较多,真有些不好意思了。。。请多包涵。。。

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
6
关闭 站长推荐上一条 /3 下一条