【STM32】ARM彙編指令

在嵌入式的學習中,編程時,總會遇到一些彙編代碼。。。

不過一想也是,嵌入式本身就偏底層,和硬件接觸,彙編代碼效率更高,總會接觸的。

-----------------------------

彙編語言是什麼?

彙編語言是程序設計語言的基礎語言,是唯一可以直接與計算機硬件打交道的語言。

 

彙編語言根據CPU的不同,也分爲:ARM彙編語言、x86彙編語言

ARM彙編指令: 
	EQU			給數字常量名取一個符號名,相當於C語言中的define
	AREA		彙編一個新的代碼段或者數據段
	SPACE 		分配內存空間
	PRESERVE8	當前文件棧需按照 8 字節對齊
	EXPORT		聲明一個標號具有全局屬性,可被外部的文件使用
	DCD			以字爲單位分配內存,要求 4 字節對齊,並要求初始化這些內存
	PROC		定義子程序,與 ENDP 成對使用,表示子程序結束
	IMPORT		聲明標號來自外部文件,跟 C 語言中的 EXTERN 關鍵字類似
	B 			跳轉到一個標號
	END         到達文件末尾 ,文件結束
	
	IF,ELSE,
	   ENDIF    彙編條件分支語句,跟 C 語言的 if else 類似
	
	MRS			加在特殊功能寄存器的值到通用寄存器
	MSR			存儲通用寄存器的值到特殊功能寄存器
	CBZ			比較,比較結果爲0就轉移
	CBNZ		比較,比較結果非0就轉移
	LDR			從存儲器中加載字到寄存器中l 是
	LDR[僞指令] 加載一個立即數或者一個地址值到一個寄存器。例如:ldr rd, = lable 如果 label 是立即數,那 Rd 等於立即數,如果 labe一個標識符,比如指針,那存到 Rd 的就是 label 這個標識符的地址
	LDRH 		從存儲器中加半字到一個寄存器中
	LDRB		從存儲器中加載字節到寄存器中
	STR			把一個寄存器按字存儲到存儲器中
	STRH 		把一個寄存器存的低【半】字存儲到存儲器中
	STRB 		把一個寄存器的低字節存儲到存儲器中
	LDMIA 		將多個字從存儲器加載到 CPU 寄存器,先操作,指針在遞增。
	STMDB 		將多個字從 CPU 寄存器存儲到存儲器,指針先遞減,再操作
	ORR 		按位或
	BX 			直接跳轉到由寄存器給定的地址
	BL 			跳轉到 標號對應的地址,並且把跳轉前的下條指令地址保存到 LR
	BLX 		跳轉到由寄存器 REG 給出的的地址,並根據 REG 的 LSB 切換處理器狀
					態 , 還 要 把 轉 移 前 的 下 條 指 令 地 址 保 存 到 LR 。 ARM(LSB=0) ,
					Thumb(LSB=1)。CM3 只在 Thumb 中運行,就必須保證 reg 的 LSB=1 否則一個fault 打過來


編譯器指令:
	WEAK		弱定義,如果外部文件聲明瞭一個標號,則優先使用外部文件定義的標號,如果外部文件沒有定義也不出錯。

	ALIGN		編譯器對指令或者數據的存放地址進行對齊,一般需要跟一個立即數,缺省表示 4 字節對齊

------再看彙編代碼並註釋

 __asm void xPortPendSVHandler( void ) //這個函數完成:上下文切換:上文保存、切換下文
 {
 extern pxCurrentTCB;       (1)//  
 extern vTaskSwitchContext; (2)//
 
 PRESERVE8              (3)//當前文件棧需按照 8 字節對齊
 
 mrs r0, psp            (4)//加在特殊功能寄存器psp的值到通用寄存器r0 
 isb                    //指令同步隔離。最嚴格:它會清洗流水線,以保證所有它前面的指令都執行完畢之後,才執行它後面的指令
 
 ldr r3, =pxCurrentTCB   (5)//加載 pxCurrentTCB 的地址到 r3
 ldr r2, [r3]            (6)//加載r3指向的內容到r2,即 r2 等於 pxCurrentTCB
 
 stmdb r0!, {r4-r11}     (7)//db:decrease before. 以 r0 作爲基址(指針先遞減,再操作)將 CPU 寄存器 r4~r11 的值存儲到任務棧,同時更新 r0 的值
 str r0, [r2]            (8)//將 r0 的值存儲到 r2 指向的內容,r2 等於 pxCurrentTCB。
                       //到這步結束,上下文切換的上文保存,完成。
					   
 stmdb sp!, {r3, r14}    (9)//將 R3 和 R14 臨時壓入堆棧
 mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY  (10)//將 configMAX_SYSCALL_INTERRUPT_PRIORITY 的值存儲到r0
 msr basepri, r0         (11)//關中斷(???)將r0的值到特殊功能寄存器basepri

 dsb   //數據同步隔離。比 DMB 嚴格: 僅當所有在它前面的存儲器訪問操作都執行完畢後,才執行在它後面的指令
 isb   //指令同步隔離
 
 bl vTaskSwitchContext   (12)//跳轉到vTaskSwitchContext的地址,即執行該函數,
 mov r0, #0              (13)//退出臨界段,開中斷,直接往 r0 寫 0
 msr basepri, r0             //再將r0中的0寫入到basepri中
 ldmia sp!, {r3, r14}    (14)//將多個字從存儲器加載到 CPU 寄存器,先操作,指針在遞增:從主堆棧中恢復寄存器 r3 和 r14 的值,此時的 sp 使用的是 MSP
 
 ldr r1, [r3]            (15)//加載 r3 指向的內容到 r1。r3 存放的是 pxCurrentTCB 的地址,即 讓 r1 等於 pxCurrentTCB。pxCurrentTCB 在上面的 vTaskSwitchContext 函數中被更新,指向了下一個將要運行的任務的 TCB。
 ldr r0, [r1]            (16)//加載 r1 指向的內容到 r0,即下一個要運行的任務的棧頂指針
 ldmia r0!, {r4-r11}     (17)//以 r0 作爲基地址(先取值,再遞增指針,LDMIA 的 IA 表示Increase After),將下一個要運行的任務的任務棧的內容加載到 CPU 寄存器 r4~r11。
 msr psp, r0             (18)//將r0的值寫到psp中:更新 psp 的值,等下異常退出時,會以 psp 作爲基地址,將任務棧中剩下的內容自動加載到 CPU 寄存器
 
 isb  //指令同步隔離
 
 bx r14                  (19)//直接跳轉到由寄存器r14給定的地址
 nop  //NOP空操作僞指令
 }

 

發佈了90 篇原創文章 · 獲贊 70 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章