社区闲人 发表于 2024-12-11 20:29:27

栗说C251与汇编语言混合编程

AI公司提供的AI32G12K128的USB例程的util.c文件里有一个函数:

WORD reverse2(WORD w)
{
    WORD ret;
   
    ((BYTE *)&ret) = ((BYTE *)&w);
    ((BYTE *)&ret) = ((BYTE *)&w);

    return ret;
}

编译后的汇编代码为:
    29: WORD reverse2(WORD w)
0xFF1316   7A370021    MOV      w(0x0021),WR6
    30: {
    31:   WORD ret;
    32:      
    33:   ((BYTE *)&ret) = ((BYTE *)&w);
0xFF131A   7E340022    MOV      WR6,#0x0022
0xFF131E   7E240000    MOV      WR4,#0x0000
0xFF1322   7E1B30      MOV      R3,@DR4
0xFF1325   7E340023    MOV      WR6,#0x0023
0xFF1329   7E240000    MOV      WR4,#0x0000
0xFF132D   7A1B30      MOV      @DR4,R3
    34:   ((BYTE *)&ret) = ((BYTE *)&w);
    35:
0xFF1330   7E340021    MOV      WR6,#w(0x0021)
0xFF1334   7E240000    MOV      WR4,#0x0000
0xFF1338   7E1B30      MOV      R3,@DR4
0xFF133B   7E340024    MOV      WR6,#0x0024
0xFF133F   7E240000    MOV      WR4,#0x0000
0xFF1343   7A1B30      MOV      @DR4,R3
    36:   return ret;
0xFF1346   7E370023    MOV      WR6,0x0023
    37: }
0xFF134A   22          RET      

用汇编代码为:
      RSEG       ?PR?REVERSE2?UTIL
      reverse2 PROC   
; line 29: WORD reverse2(WORD w)
      MOV      WR4,WR6
      MOV      R6,R5
      MOV      R7,R4
      RET      
      ENDP

然后将c文件替换为汇编代码文件,重新编译后,进入debug汇编界面,
在usb.c文件里找到调用reverse2(WORD w)函数处:

   244:             Setup.wLength = reverse2(Setup.wLength);
0xFF0D8C   7E37000E    MOV      WR6,0x000E
0xFF0D90   12153A      LCALL    reverse2(C:0x153A)
0xFF0D93   7A37000E    MOV      0x000E,WR6

再找到reverse2(C:0x153A)处:
    75:         MOV      WR4,WR6
0xFF153A   7D23      MOV      WR4,WR6
    76:         MOV      R6,R5
0xFF153C   7C65      MOV      R6,R5
    77:         MOV      R7,R4
0xFF153E   7C74      MOV      R7,R4
    78:         RET      
0xFF1540   22          RET      

验证OK!




health 发表于 2024-12-11 22:21:35

大小端转换?
uint16_t reverse2(uint16_t w)
{
    return (w >> 8) | (w << 8);
}

这种非常简单的操作,用函数调用效率太低了,函数调用3个时钟,返回又3个时钟,调用前后的参数传递和返回值也需要消耗时钟周期,而真正的操作只有两三条指令而已。

如果要转换数据放在寄存器A和B,(WR10),只需一条指令,
XCH A,B

社区闲人 发表于 2024-12-12 07:58:29

确实,用 return (w >> 8) | (w << 8); 可以编译出高效的代码:

    30: WORD reverse2(WORD w)
    31: {
    32:   return (w >> 8) | (w << 8);
0xFF153A   6C67      XRL      R6,R7
0xFF153C   6C76      XRL      R7,R6
0xFF153E   6C67      XRL      R6,R7
    33: }
0xFF1540   22          RET

bkeuqoaq 发表于 2024-12-12 08:34:10

转换成通用指针确实慢

社区闲人 发表于 2024-12-12 08:35:23

同样道理,对于函数:
DWORD reverse4(DWORD d)
{   
    DWORD ret;
   
    ((BYTE *)&ret) = ((BYTE *)&d);
    ((BYTE *)&ret) = ((BYTE *)&d);
    ((BYTE *)&ret) = ((BYTE *)&d);
    ((BYTE *)&ret) = ((BYTE *)&d);

    return ret;
}

改为:
return (d << 24) | (d << 16) & 0xff0000 | ((d >> 16) & 0xff00) | (d >> 24) ;
也可以编译出高效的代码:
    17: DWORD reverse4(DWORD d)
    18: {   
0xFF186B   7F21      MOV      DR8,DR4
    19:   return (d << 24) | (d << 16) & 0xff0000 | ((d >> 16) & 0xff00) | (d >> 24) ;
0xFF186D   7D03      MOV      WR0,WR6
0xFF186F   6C00      XRL      R0,R0
0xFF1871   7C41      MOV      R4,R1
0xFF1873   6C55      XRL      R5,R5
0xFF1875   4D20      ORL      WR4,WR0
0xFF1877   7D14      MOV      WR2,WR8
0xFF1879   6C33      XRL      R3,R3
0xFF187B   7D02      MOV      WR0,WR4
0xFF187D   0A38      MOVZ   WR6,R8
0xFF187F   4D31      ORL      WR6,WR2
    20: }
0xFF1881   22          RET      

用汇编最高效:
      MOV      DR8,DR4
      MOV      R4,R11
      MOV      R5,R10
      MOV      R6,R9
      MOV      R7,R8
      RET      
      ENDP

bkeuqoaq 发表于 2024-12-12 09:08:36

还是ARM NB一条指令搞定 __rev

bkeuqoaq 发表于 2024-12-12 09:11:01

;DWORD reverse4(DWORD d)
        PUSH         R7
        PUSH        R6
        PUSH        R5
        PUSH        R4
        POP                DR4
        RET

bkeuqoaq 发表于 2024-12-12 09:18:30

;DWORD reverse4(DWORD d)
        PUSH        DR4
        POP                R4
        POP                R5
        POP                R6
        POP                R7
        RET
页: [1]
查看完整版本: 栗说C251与汇编语言混合编程