⽤51汇编完整写⼀个函数
⽬录
本⽂将以查表法CRC为例,完整介绍如何⽤汇编写⼀个函数,以及如何传⼊函数参数、获得返回值、被其他函数调⽤。
最近⽤汇编写了⼀个查表法CRC16校验函数,其中遇到很多困难,⾛了很多弯路,特此记录,请⼤家共勉。请结合最后的附录代码看前⾯的解释,会好理解很多。汇编代码基本就是按照C代码⼀句⼀句翻译的。
1.汇编函数如何传⼊参数
需要改写的C函数如下:
u16 Crc16withTable(u8 *buf, u16 seeds, u16 len)
⾸先想到的就是怎么传⼊参数,因为汇编不像C语⾔⼀样可以⽤括号表⽰形参,那么如何给汇编函数传⼊参数呢?这涉及到不同芯⽚架构的规定,C51规定如下:
⼤家可以在keil4软件中的Help->uVision Help->搜索中搜索Parameter Passing关键字,就会看到这段信息。翻译如下:
C51编译器在CPU寄存器中最多传递三个函数参数。这显著提⾼了系统性能,因为不需要将参数写⼊内存并从内存中读取参数。参数传递可以通过REGPARMS和NOREGPARMS控制指令进⾏控制。下表列出了⽤于不同参数和数据类型的寄存器。
如果没有寄存器可⽤来传递参数,或者涉及的参数太多,则为这些额外的参数使⽤固定的内存位置。
对上表进⾏解释:
1. ⾸先,传递的参数不能超过3个,如果超过3个,需要使⽤外部ram的固定地址存放。
2. 其次,从表中可以看出,传递的参数类型不同,允许传递的参数个数也将发⽣变化。
3. 最后,不同参数类型对应的寄存器不同。
以本⽂的函数为例,传⼊的参数有3个,分别是指向u8的指针buf、2byte⼤⼩的seeds、2byte⼤⼩的len。
第1个参数对应表的第1⾏,buf是⼀个指针,在51中地址是16位,所以buf本质上是2byte 指针,所以寄存器R6和R7分别存放buf的⾼字节和低字节,可以参考汇编代码第60⾏和第63⾏,直接调⽤R6和R7就是调⽤buf的⾼字节和低字节;
第2个参数对应表的第2⾏,seed也是2byte,所以它占⽤R4和R5两个寄存器;
第3个参数对应表的第3⾏,len也是2byte,所以它占⽤R2和R3两个寄存器。
当你在调⽤这个函数时,给函数传⼊实参,然后程序就会跳转到汇编代码⼀⾏⼀⾏执⾏,这时候你传⼊的实参就已经在寄存器中了,⾄于各寄存器⾥⾯放哪个参数的值,上⼀段已经讲的很清楚了。
2.汇编函数如何返回结果
有的函数执⾏完后需要返回结果,这个结果可能是1byte,也可能是2byte,也可能是4byte。但是汇编不像C语⾔函数直接⽤return就可以,与第1章所述⼀样,汇编函数的返回值也是放在寄存器中的。如
本⽂汇编函数最后4⾏,是将计算结果放在了R6和R7两个寄存器中。那么在执⾏完函数返回到C语⾔中时,芯⽚⾃动将R6和R7中的值取出,作为返回值返回。
这⾥只是知道2byte返回值放在R6和R7寄存器中,但是不知道1byte和4byte时应该放在哪个寄存器,也没有到资料。⼤家实际⽤的时候可以试⼀下,看放在哪个寄存器⾥可以返回正确值。
3.汇编函数如何在C语⾔中被调⽤
我⾃⼰的⽅法是:
1. 将需要⽤汇编写的函数单独新建⼀个.asm⽂件,然后在这个⾥⾯写汇编函数;
2. 写汇编函数时需要特别注意:如果有参数,需要在函数名前加“_”,表⽰这个函数时带参数的,参考本⽂汇编代码第1⾏;
3. 汇编函数最后⼀定加“END”,参考本⽂汇编代码最后1⾏;
4. 在调⽤这个函数的地⽅,先⽤“extern”声明⼀下这个函数,声明就能直接⽤C语⾔函数的格式就⾏,如下:
extern u16 Crc16withTable(u8 *buf, u16 seeds, u16 len);
5. 最后将这个.asm⽂件添加到⼯程即可。
附录A:查表法crc校验C代码:
/*****************************************************************************
*function name:Crc16withTable
*function: ⽤查表法计算CRC
*input: addr:字符串起始地址;len :字符串长度;crcHighTable,crcLowTable:⽤到的表格
*output:⽆
******************************************************************************/
u16 Crc16withTable(u8 *buf, u16 seeds, u16 len)
{
u8 crcHi = 0x00;
u8 crcLo = 0x00;
u8 index;
u16 crc;
u16 i;
for (i=0;i<len;i+=2)
{
index = crcLo ^ *(buf+i+1);//低8位异或,得到表格索引值
crcLo = crcHi ^ crcHighTable[index];
crcHi = crcLowTable[index];
index = crcLo ^ *(buf+i);//低8位异或,得到表格索引值
crcLo = crcHi ^ crcHighTable[index];
crcHi = crcLowTable[index];
}
crc = (u16)(crcHi<<8 | crcLo);
return crc;
}
附录B:查表法crc校验汇编代码:
PUBLIC _Crc16withTable ;函数名前加"_",表⽰此函数带参数
;u16 Crc16withTable(u8 *buf, u16 seeds, u16 len)
PR__Crc16withTable SEGMENT CODE
RSEG ?PR?_Crc16withTable
CRC16HighTable: DB 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H, 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H
DB 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H, 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H
DB 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H, 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H
DB 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H, 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H
DB 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H, 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H
DB 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H, 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H
DB 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H, 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H
DB 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H, 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H
DB 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H, 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H
DB 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H, 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H
DB 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H, 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H
DB 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H, 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H
DB 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H, 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H
DB 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H, 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H
DB 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H, 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H
DB 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H, 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H
DB 00H,0c1H, 81H, 40H, 01H,0c0H, 80H, 41H, 01H,0c0H, 80H, 41H, 00H,0c1H, 81H, 40H
CRC16LowTable: DB 00H, 0c0H,0c1H, 01H,0c3H, 03H, 02H,0c2H,0c6H, 06H, 07H,0c7H, 05H,0c5H,0c4H, 04H DB 0ccH, 0cH, 0dH,0cdH, 0fH,0cfH,0ceH, 0eH, 0aH,0caH,0cbH, 0bH,0c9H, 09H, 08H,0c8H
DB 0d8H, 18H, 19H,0d9H, 1bH,0dbH,0daH, 1aH, 1eH,0deH,0dfH, 1fH,0ddH, 1dH, 1cH,0dcH
DB 14H, 0d4H,0d5H, 15H,0d7H, 17H, 16H,0d6H,0d2H, 12H, 13H,0d3H, 11H,0d1H,0d0H, 10H
DB 0f0H, 30H, 31H,0f1H, 33H,0f3H,0f2H, 32H, 36H,0f6H,0f7H, 37H,0f5H, 35H, 34H,0f4H
DB 3cH, 0fcH,0fdH, 3dH,0ffH, 3fH, 3eH,0feH,0faH, 3aH, 3bH,0fbH, 39H,0f9H,0f8H, 38H
DB 28H, 0e8H,0e9H, 29H,0ebH, 2bH, 2aH,0eaH,0eeH, 2eH, 2fH,0efH, 2dH,0edH,0ecH, 2cH
DB 0e4H, 24H, 25H,0e5H, 27H,0e7H,0e6H, 26H, 22H,0e2H,0e3H, 23H,0e1H, 21H, 20H,0e0H
DB 0a0H, 60H, 61H,0a1H, 63H,0a3H,0a2H, 62H, 66H,0a6H,0a7H, 67H,0a5H, 65H, 64H,0a4H
DB 6cH, 0acH,0adH, 6dH,0afH, 6fH, 6eH,0aeH,0aaH, 6aH, 6bH,0abH, 69H,0a9H,0a8H, 68H
DB 78H, 0b8H,0b9H, 79H,0bbH, 7bH, 7aH,0baH,0beH, 7eH, 7fH,0bfH, 7dH,0bdH,0bcH, 7cH
DB 0b4H, 74H, 75H,0b5H, 77H,0b7H,0b6H, 76H, 72H,0b2H,0b3H, 73H,0b1H, 71H, 70H,0b0H
DB 50H, 90H, 91H, 51H, 93H, 53H, 52H, 92H, 96H, 56H, 57H, 97H, 55H, 95H, 94H, 54H
DB 9cH, 5cH, 5dH, 9dH, 5fH, 9fH, 9eH, 5eH, 5aH, 9aH, 9bH, 5bH, 99H, 59H, 58H, 98H
DB 88H, 48H, 49H, 89H, 4bH, 8bH, 8aH, 4aH, 4eH, 8eH, 8fH, 4fH, 8dH, 4dH, 4cH, 8cH
DB 44H, 84H, 85H, 45H, 87H, 47H, 46H, 86H, 82H, 42H, 43H, 83H, 41H, 81H, 80H, 40H
_Crc16withTable:
;
R6放addr⾼字节
;R7放addr低字节
;R4放seeds⾼字节,即crcHi
;R5放seeds低字节,即crcLo
;R2放len⾼字节
;R3放len低字节
MOV R0,#0x00 ;R0放i⾼字节
MOV R1,#0x00 ;R1放i低字节
BEGINLOOP:
CRL C ;清除结借位(进位)标志位
MOV A,R1
SUBB A,R3
MOV A,R0
SUBB A,R2
JNC ENDLOOP
;index=crcLo^*(buf+i+1)
MOV A,R7 ;buf低字节->A
ADD A,R1 ;buf低字节+i低字节
MOV DPL,A ;低字节之和->PDL
MOV A,R6 ;buf⾼字节->A
ADDC A,R0 ;buf⾼字节+i⾼字节
MOV DPH,A ;⾼字节之和->DPH
MOV A,#0x01
MOVC A,@A+DPTR ;*(buf+i+1)
XRL A,R5 ;A=index=*(buf+i+1)^crcLo
MOV B,A ;B=index
;crcLo=crcHi^CRCHighTable[index]
MOV DPTR,#CRC16HighTable;获取表的⾸地址
一个完整的c语言程序MOVC A,@A+DPTR ;CRCHighTable[index]
XRL A,R4 ;CRCHighTable[index]^crcHi
MOV R5,A ;crcLo=A,更新crcLo的值
MOV R5,A ;crcLo=A,更新crcLo的值
;crcHi=CRC16LowTable[index]
MOV A,B ;index->A
MOV DPTR,#CRC16LowTable ;获取表的⾸地址 MOVC A,@A+DPTR ;A=CRC16LowTable[index] MOV R4,A ;crcHi=A,更新crcHi的值
;第2次循环
;index=crcLo^*(buf+i)
MOV A,R7 ;buf低字节->A
CLR C
ADD A,R1 ;buf低字节+i低字节
MOV DPL,A ;低字节之和->PDL
MOV A,R6 ;buf⾼字节->A
ADDC A,R0 ;buf⾼字节+i⾼字节
MOV DPH,A ;⾼字节之和->DPH
CLR A
MOVC A,@A+DPTR ;*(buf+i)
XRL A,R5 ;A=index=*(buf+i)^crcLo
MOV B,A ;B=index
;crcLo=crcHi^CRCHighTable[index]
MOV DPTR,#CRC16HighTable;获取表的⾸地址 MOVC A,@A+DPTR ;CRCHighTable[index]
XRL A,R4 ;CRCHighTable[index]^crcHi
MOV R5,A ;crcLo=A,更新crcLo的值
;crcHi=CRC16LowTable[index]
MOV A,B ;index->A
MOV DPTR,#CRC16LowTable ;获取表的⾸地址 MOVC A,@A+DPTR ;A=CRC16LowTable[index] MOV R4,A ;crcHi=A,更新crcHi的值
;i=i+2
MOV A,#0x02
CLR C
ADD A,R1
MOV R1,A ;更新i低字节
CLR A
ADDC A,R0 ;
MOV R0,A ;更新i⾼字节
LJMP BEGINLOOP ;⽆条件跳转⾄循环开始部分
ENDLOOP:
MOV A,R4 ;
MOV R6,A
MOV A,R5
MOV R7,A
RET
END
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论