天天看點

STM32單片機-彙編指令1專門的跳轉指令

目錄:

1、ldr/str/mov指令

1)LDR指令   2)STR和LDRB指令   3)MOV指令   4)使用示例

2、MOVS指令

3、LDM表示裝載,STM表示存儲

4、teq指令

5、使用tst來檢查是否設定了特定的位

6、'^'的了解

7、spsr_cxsf,cpsr_cxsf的了解

8、cpsr的了解

9、指令字尾和條件判斷

10、B、BL、BX、BLX 和 BXJ指令的差別

1)B 指令   2)BL 指令   3)BLX 指令   4)BX 指令和BXJ指令   5)總結

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

說明:

STM32單片機彙編指令使用一

STM32單片機彙編指令使用二

ARM單片機彙編指令的查找見“STM32單片機二之十五、查找彙編指令”。

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

.macro restore_user_regs //宏

   ldr r1,[sp, #S_PSR]

   ldr lr,[sp, #S_PC]!   @ !用來控制基址變址尋址的最終新位址是否進行回寫操作,

                                  @ 執行ldr之後sp被回寫成sp+#S_PC基址變址尋址的新位址

   msrspsr,r1              @ 把cpsr的值儲存到spsr中

   ldmdb sp,{r0 - lr}^@lr=[sp-1*4],r13=[sp-2*4],r12=[sp-3*4],......,r0=[sp-15*4]

                                 @ 因為沒對pc指派,是以^的表示将資料恢複到User模式的[r0-lr]寄存器組中[gliethttp]

   mov r0,r0 

   add sp,sp,#S_FRAME_SIZE - S_PC

   movs pc,lr

.endm

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

1、ldr/str/mov指令

1)LDR指令

LDR格式:LDR{條件}   目的寄存器  <存儲器位址>

LDR作用:将存儲器位址所指位址處連續的4個位元組(1個字)的資料傳送到目的寄存器

比如想把資料從記憶體中某處讀取到寄存器中,隻能使用ldr

比如:ldr r0, 0x12345678

就是把0x12345678這個位址中的值存放到r0。

而mov不能幹這個活,mov隻能在寄存器之間移動資料,或者把立即數移動到寄存器中。

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

2)STR和LDRB指令

STR格式:STR{條件}  源寄存器,<存儲器位址>

STR作用:STR指令用于從源寄存器中将一個32位的字資料傳送到存儲器中。該指令在程式設計中比較常用,尋址方式靈活多樣,使用方式可參考指令LDR。 

LDRB:位元組資料加載指令

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

3)MOV指令

MOV格式:mov source, destination

MOV作用:source 和 destination 的值可以是記憶體位址,存儲在記憶體中的資料值,指令語句中定義的資料值,或者寄存器。

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

4)使用示例

   ldr ip,[sp],#4 //将sp中内容存入ip,之後sp=sp+4;

   ldr ip,[sp,#4] //将sp+4這個新位址下内容存入ip,之後sp值保持不變

   ldr ip,[sp,#4]! //将sp+4這個新位址下内容存入ip,之後sp=sp+4将新位址值賦給sp

   str ip,[sp],#4 //将ip存入sp位址處,之後sp=sp+4;

   str ip,[sp,#4] //将ip存入sp+4這個新位址,之後sp值保持不變

   str ip,[sp,#4]! //将ip存入sp+4這個新位址,之後sp=sp+4将新位址值賦給sp

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

2、MOVS指令

   movs r1,#3 ; //movs将導緻ALU被更改,因為r1指派非0,即操作結果r0非0,是以ALU的Z标志清0

   bne 1f  ; //因為Z=0,說明不等,是以向前跳到标号1:所在處繼續執行其他語句

MOVS pc,r14_und; //cpsr(狀态寄存器)←spsr_und(備份狀态寄存器),pc←r14_und

相關指令詳見“嵌入式網絡那些事LwIP協定深度剖析與實戰演練P42下方”。

MOVS總是會影響cpsr, 包括N,Z,C标志位,執行MOVS pc,lr(也就是r14寄存器)時,cpsr會被spsr覆寫,如上。核心态,USER和SYSTEM模式下沒有spsr。

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

3、LDM表示裝載,STM表示存儲

   LDMED LDMIB 預先增加裝載

   LDMFD LDMIA 過後增加裝載

   LDMEA LDMDB 預先減少裝載

   LDMFA LDMDA 過後減少裝載

   STMFA STMIB 預先增加存儲

   STMEA STMIA 過後增加存儲

   STMFD STMDB 預先減少存儲

   STMED STMDA 過後減少存儲

注意ED不同于IB;隻對于預先減少裝是相同的.在存儲的時候,ED是過後減少的.

FD、ED、FA、和 EA 指定是滿棧還是空棧,是升序棧還是降序棧.

對于存儲STM而言

先加後存 FA 姑且這麼來記,先加(first add),存資料

後加先存 EA 姑且這麼來記,存資料,後加end add

先減後存 FD 姑且這麼來記,先減first dec,存資料

後減先存 ED 姑且這麼來記,存資料,後減end dec

然後記憶LDM,LDM是STM的反相彈出動作,是以

因為是先加後存,是以後減先取 FA 就成了與STM對應的取資料,後減

因為是後加先存,是以先減後取 EA 就成了與STM對應的先減,取資料

因為是先減後存,是以後加先取 FD 就成了與STM對應的取資料,後加

因為是後減先存,是以先加後取 ED 就成了與STM對應的先加,取資料

我想通過上面的變态方式可以比較容易的記住這套指令[gliethttp]

一個滿棧的棧指針指向上次寫的最後一個資料單元,而空棧的棧指針指向第一個空閑單元.

一個降序棧是在記憶體中反向增長(就是說,從應用程式空間結束處開始反向增長)而升序棧在記憶體中正向增長. 

其他形式簡單的描述指令的行為,意思分别是

IA過後增加(Increment After)、

IB預先增加(Increment Before)、

DA過後減少(Decrement After)、

DB預先減少(Decrement Before).

RISC OS使用傳統的滿降序棧.在使用符合APCS規定的編譯器的時候,它通常把你的棧指針設定在應用程式空間的

結束處并接着使用一個FD(滿降序-Full Descending)棧.如果你與一個進階語言(BASIC或C)一起工作,你将别無選擇.

棧指針(傳統上是R13)指向一個滿降序棧.你必須繼續這個格式,或則建立并管理你自己的棧.

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

4、teq指令

teq r1,#0      //r1-0,将結果送入狀态标志,如果r1和0相減的結果為0,那麼ALU的Z置位,否則Z清0

bne reschedule//ne表示Z非0,即:不等,那麼執行reschedule函數

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

5、使用tst來檢查是否設定了特定的位

tst r1,#0x80 //按位and操作,檢測r1的0x1<<7,即第7位是否置1,按位與之後結果為0,那麼ALU的Z置位

beq reset    //如果Z置位,即:以上按位與操作結果是0,那麼跳轉到reset标号執行

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

6、'^'的了解

'^'是一個字尾标志,不能在User模式和Sys系統模式下使用該标志.該标志有兩個存在目的:

1)對于LDM操作,同時恢複的寄存器中含有pc(r15)寄存器,那麼指令執行的同時cpu自動将spsr拷貝到cpsr中

如:在IRQ中斷傳回代碼中[如下為ads環境下的代碼gliethttp]

ldmfd {r4}           //讀取sp中儲存的的spsr值到r4中

msr spsr_cxsf,r4     //對spsr的所有控制為進行寫操作,将r4的值全部注入spsr

ldmfd {r0-r12,lr,pc}^//當指令執行完畢,pc跳轉之前,将spsr的值自動拷貝到cpsr中[gliethttp]

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

2)資料的送入、送出發生在User使用者模式下的寄存器,而非目前模式寄存器

如:ldmdb sp,{r0 - lr}^;表示sp棧中的資料回複到User分組寄存器r0-lr中,而不是恢複到目前模式寄存器r0-lr

當然對于User,System,IRQ,SVC,Abort,Undefined這6種模式來說[gliethttp]r0-r12是共用的,隻是r13和r14

   為分别獨有,對于FIQ模式,僅僅r0-r7是和前6中模式的r0-r7共用,r8-r14都是FIQ模式下專有.

STM32單片機-彙編指令1專門的跳轉指令

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

7、spsr_cxsf,cpsr_cxsf的了解

c - control field maskbyte(PSR[7:0])

x - extension field maskbyte(PSR[15:8])

s - status field maskbyte(PSR[23:16)

f - flags field maskbyte(PSR[31:24]).

老式聲明方式:cpsr_flg,cpsr_all在ADS中已經不在支援

cpsr_flg對應cpsr_f

cpsr_all對應cpsr_cxsf

需要使用專用指令對cpsr和spsr操作:mrs,msr

mrs tmp,cpsr      //讀取CPSR的值

bic tmp,tmp,#0x80 //如果第7位為1,将其清0

msr cpsr_c,tmp    //對控制位區psr[7:0]進行寫操作

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

8、cpsr的了解

CPSR = Current Program Status Register

SPSR = Saved Program Status Registers

CPSR寄存器(和儲存它的SPSR寄存器)

STM32單片機-彙編指令1專門的跳轉指令

(上圖)

N,Z,C,V稱為ALU狀态标志

N:如果結果是負數則置位

Z:如果結果是零則置位

C:如果發生進位則置位

V:如果發生溢出則置位

I:置位表示禁用IRQ中斷,清0表示使能IRQ

F:置位表示禁用FIQ中斷,清0表示使能FIQ

T:置位表示系統運作在Thumb态,清0表示運作在ARM态

M[4:0]:

10000 User模式,和System系統模式一樣

10001 FIQ模式

10010 IRQ模式

10011 SVC超級管理模式

10111 Abort資料異常模式

11011 Undefined未定義指令模式

11111 System系統模式,和User模式一樣

舉例:

ands r2,r2,#7 使用運算結果改變标志位,如果運算結果r2=0,那麼Z置位,EQ相等判斷成立

subs r2,r2,#1 使用運算結果改變标志位,如果運算結果r2=0,那麼Z置位,EQ相等判斷成立

beq wordcopy

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

9、指令字尾和條件判斷

STM32單片機-彙編指令1專門的跳轉指令

 (上圖)

EQ : 等于

NE : 不等

CS : 無符号>=

CC : 無符号<</span>

MI : 負數

PL : 非負[>=0]

VS : 溢出

VC : 無溢出

HI : 無符号>

LS : 無符号<=

GE : 有符号>=

LT : 有符号<</span>

GT : 有符号>

LE : 有符号<=

AL : 總是[預設]

對于arm彙編指令,可以參考linux核心的arch/arm目錄,那裡的彙編指令很豐富[gliethttp_20080603]

__CopyFromStart

;    ldr     r3, [r9],#4

;    str     r3, [r7], #4

;    sub   r8, r8, #4

    ldrb   r3, [r9], #1

    strb   r3, [r7], #1

    sub   r8, r8, #1

    cmp  r8, #0

    bgt    __CopyFromStart

    b       __JumpToBootImage

    __JumpToBootImage

    MOV     pc, r0

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

10、B、BL、BX、BLX 和 BXJ指令的差別

跳轉指令用于實作程式流程的跳轉,在 ARM 程式中有兩種方法可以實作程式流程的跳轉:

使用專門的跳轉指令。

直接向程式計數器 PC 寫入跳轉位址值。

通過向程式計數器 PC 寫入跳轉位址值,可以實作在 4GB 的位址空間中的任意跳轉,在跳轉之前結合使用

MOV LR , PC

等類似指令,可以儲存下一條指令位址作為将來的傳回位址值,進而實作在 4GB 連續的線性位址空間的子程式調用。

專門的跳轉指令

B、BL、BX、BLX 和 BXJ:

跳轉、帶連結跳轉(帶傳回的跳轉)、跳轉并切換指令集、帶連結跳轉并切換指令集(帶傳回的跳轉并切換指令集)、跳轉并轉換到 Jazelle 狀态。

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

1)B 指令

B 指令的格式為:B{條件} 目标位址

B 指令是最簡單的跳轉指令。一旦遇到一個 B 指令,ARM 處理器将立即跳轉到給定的目标位址,從那裡繼

續執行。注意存儲在跳轉指令中的實際值是相對目前PC 值的一個偏移量,而不是一個絕對位址,它的值由彙編器來計算(參考尋址方式中的相對尋址)。它是 24 位有符号數,左移兩位後有符号擴充為 32 位,表示的有效偏移為 26 位(前後32MB 的位址空間)。以下指令:

B Label ;程式無條件跳轉到标号 Label 處執行

CMP R1 ,# 0 ;當 CPSR 寄存器中的 Z 條件碼置位時,程式跳轉到标号 Label 處執行

BEQ Label

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

2)BL 指令

BL 指令的格式為:BL{條件} 目标位址

BL 是另一個跳轉指令,但跳轉之前,會在寄存器R14 中儲存PC 的目前内容,是以,可以通過将R14 的内容重新加載到PC 中,來傳回到跳轉指令之後的那個指令處執行。該指令是實作子程式調用的一個基本但常用的手段。以下指令:

BL Label ;當程式無條件跳轉到标号 Label 處執行時,同時将目前的 PC 值儲存到 R14 中

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

3)BLX 指令

BLX 指令的格式為:BLX 目标位址

BLX 指令從ARM 指令集跳轉到指令中所指定的目标位址,并将處理器的工作狀态有ARM 狀态切換到Thumb 狀态,該指令同時将PC 的目前内容儲存到寄存器R14 中。是以,當子程式使用Thumb 指令集,而調用者使用ARM 指令集時,可以通過BLX 指令實作子程式的調用和處理器工作狀态的切換。

同時,子程式的傳回可以通過将寄存器R14 值複制到PC 中來完成。

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

4)BX 指令和BXJ指令

BX 指令的格式為:BX{條件} 目标位址

BX 指令跳轉到指令中所指定的目标位址,目标位址處的指令既可以是ARM 指令,也可以是Thumb指令。

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

5)總結

文法

op1{cond}{.W} label

op2{cond} Rm

其中:

op1

是下列項之一:

B

跳轉。

BL

帶連結跳轉

BLX

帶連結跳轉并切換指令集。

op2

是下列項之一:

BX

跳轉并切換指令集。

BLX

帶連結跳轉并切換指令集。

BXJ

跳轉并轉換為 Jazelle 執行。

cond

是一個可選的條件代碼。 cond 不能用于此指令的所有形式。

.W

是一個可選的指令寬度說明符,用于強制要求在 Thumb-2 中使用 32 位 B 指令。

label

是一個程式相對的表達式。

Rm

是一個寄存器,包含要跳轉到的目标位址。

操作

所有這些指令均會引發跳轉,或跳轉到 label,或跳轉到包含在 Rm 中的位址處。 此外:

BL 和 BLX 指令可将下一個指令的位址複制到 lr(r14,連結寄存器)中。

BX 和 BLX 指令可将處理器的狀态從 ARM 更改為 Thumb,或從 Thumb 更改為 ARM。

BLX label 無論何種情況,始終會更改處理器的狀态。

BX Rm 和 BLX Rm 可從 Rm 的位 [0] 推算出目标狀态:

如果 Rm 的位 [0] 為 0,則處理器的狀态會更改為(或保持在)ARM 狀态

如果 Rm 的位 [0] 為 1,則處理器的狀态會更改為(或保持在)Thumb 狀态。

BXJ 指令會将處理器的狀态更改為 Jazelle

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