栗说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!
大小端转换?
uint16_t reverse2(uint16_t w)
{
return (w >> 8) | (w << 8);
}
这种非常简单的操作,用函数调用效率太低了,函数调用3个时钟,返回又3个时钟,调用前后的参数传递和返回值也需要消耗时钟周期,而真正的操作只有两三条指令而已。
如果要转换数据放在寄存器A和B,(WR10),只需一条指令,
XCH A,B
确实,用 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 转换成通用指针确实慢 同样道理,对于函数:
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
还是ARM NB一条指令搞定 __rev ;DWORD reverse4(DWORD d)
PUSH R7
PUSH R6
PUSH R5
PUSH R4
POP DR4
RET ;DWORD reverse4(DWORD d)
PUSH DR4
POP R4
POP R5
POP R6
POP R7
RET
页:
[1]