LDMIA、LDMIB、LDMDB、LDMDA、STMIA、LDMFD、LDMFA、LDMED、LDMEA指令詳解


簡介:

ARM指令中多數據傳輸共有兩種:

LDM:(load  much)多數據加載,將地址上的值加載到寄存器上

STM:(store much)多數據存儲,將寄存器的值存到地址上

主要用途:現場保護、數據復制、參數傳送等,共有8種模式(前面4種用於數據塊的傳輸,后面4種是堆棧操作)如下:

(1)IA:(Increase After) 每次傳送后地址加4,其中的寄存器從左到右執行,例如:STMIA R0,{R1,LR} 先存R1,再存LR

(2)IB:(Increase Before)每次傳送前地址加4,同上

(3)DA:(Decrease After)每次傳送后地址減4,其中的寄存器從右到左執行,例如:STMDA R0,{R1,LR} 先存LR,再存R1

(4)DB:(Decrease Before)每次傳送前地址減4,同上

(5)FD:  滿遞減堆棧 (每次傳送前地址減4)

(6)FA:  滿遞增堆棧 (每次傳送后地址減4)

(7)ED:  空遞減堆棧 (每次傳送前地址加4)

(8)EA:  空遞增堆棧 (每次傳送后地址加4)

注意:其中在數據塊的傳輸中是STMMDB和LDMIA對應,STMMIA和LDMDB對應

而在堆棧操作是STMFD和LDMFD對應,STMFA和LDMFA對應

 

格式:

LDM{cond}  mode  Rn{!}, reglist{^}

STM{cond}  mode  Rn{!}, reglist{^}

其中

 Rn:基址寄存器,裝有傳送數據的起始地址,Rn不允許為R15;

 !:表示最后的地址寫回到Rn中;

 reglist:可包含多於一個寄存器范圍,用“,”隔開,如{R1,R2,R6-R9},寄存器由小到大順序排列;

 ^:不允許在用戶模式和系統模式下運行

 

 

數據塊的傳輸-實例:


Ldr R1,=0x10000000          //傳送數據的起始地址0x10000000     

LDMIB R1!,{R0,R4-R6}      //從左到右加載,相當於 LDR R0,10000004  LDR R4,10000008... ...

/*傳送前地址加+4,

所以地址加4,R0=0X1000004地址里的內容,

地址加4,R4=0X10000008地址里的內容,

地址加4,R5=0X1000000C地址里的內容,

地址加4,R6=0X10000010 地址里的內容,

由於!, 最后的地址寫回到R1中,R1=0X10000010   */


 

Ldr R1,=0x10000000          //傳送數據的起始地址0x10000000        

 

LDMIA R1!,{R0,R4-R6}         //從左到右加載,相當於 LDR R0,10000000  LDR R4,10000004... ...

/*傳送后地址加+4,

所以R0=0X10000000地址里的內容,地址加4,

R4=0X10000004地址里的內容,地址加4,

R5=0X10000008地址里的內容,地址加4,

R6=0X1000000C 地址里的內容,地址加4,

由於!,最后的地址寫回到R1中,所以R1=0X10000010   */


LDR R1,=0x10000000          //傳送數據的起始地址0x10000000        

 

LDR R4,=0X10

LDR R5,=0X20

LDR R6,=0X30

STMIB R1,{R4-R6}          //從左到右加載,相當於STR [R4],0X10000004    STR [R5],0X10000008 .....

/*傳送前地址加+4,所以0X10000004地址=0X10,0X10000008地址=0X20,0X1000000C地址=0X30 */


 

Ldr R1,=0x10000000        //傳送數據的起始地址0x10000000  

LDR R4,=0X10

LDR R5,=0X20

LDR R6,=0X30           

STMIA R1!,{R4-R6 }     

/*傳送后地址加+4,所以0X10000000地址=0X10,0X10000004地址=0X20,0X10000008地址=0X30,由於!,最后的地址寫回到R1中,所以R1=0X1000000C  */


中斷實例(利用STMDB和LDMIA保護現場,然后通過LR寄存器返回

1.先設置棧sp,用於后面使用stmdb存儲寄存器數據

2.當產生異常時,便進入中斷:

sub lr, lr, #4                  

 //首先將lr-4,因為arm流水線,lr=當前pc+8,由於pc+4段沒有執行,所以lr=(當前pc+8)-4;
stmdb sp!, { r0-r12,lr }  

//每次傳送前-4,由於遞減,所以從右往左存儲寄存器

//所以sp-4=lr,sp-8=r12,... sp-56=r0; 由於!,所以最后的地址寫回到sp中,sp=sp-56;
 

ldr lr, =int_return  //設置返回地址

ldr pc, =EINT_Handle //進入中斷服務函數,如果中途返回就會調用pc=lr,即可執行int_return;

int_return:
ldmia sp!, { r0-r12,pc }^  

//每次傳送后+4,所以從左往右加載數據到寄存器

//所以r0=sp, r1=sp+4,...pc=sp+52;由於!,所以最后地址寫回到sp中,sp=sp+56;

//此時,sp=sp+56就等於最初棧頂值,pc=lr,然后返回到異常發生前的相應位置繼續執行。

//^  ^表示將spsr的值復制到cpsr,因為異常返回后需要恢復異常發生前的工作狀態


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM