用51彙編完整寫一個函數

目錄

1.彙編函數如何傳入參數

2.彙編函數如何返回結果

3.彙編函數如何在C語言中被調用

附錄A:查表法crc校驗C代碼:

附錄B:查表法crc校驗彙編代碼:


本文將以查表法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 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;獲取表的首地址
	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的值
	
;第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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章