【ARM】Load Store指令

00. 目錄

01. Load/Store指令概述

Load/Store 內存訪問指令在 ARM 寄存器和存儲器之間傳送數據。ARM 指令中有 3 種基本的數據傳送指令。

(1)單寄存器 Load/Store 指令(Single Register),這些指令在 ARM 寄存器和存儲器之間提供更靈活的單數據項傳送方式。數據項可以是字節、16 位半字或 32 位字。

(2)多寄存器 Load/Store 內存訪問指令。這些指令的靈活性比單寄存器傳送指令差,但可以使大量的數據更有效地傳送。它們用於進程的進入和退出、保存和恢復工作寄存器及複製存儲器中的一塊數據。

(3)單寄存器交換指令(Single Register Swap)。這些指令允許寄存器和存儲器中的數值進行交換,在一條指令中有效地完成 Load/Store 操作。它們在用戶級編程中很少用到。它的主要用途是在多處理器系統中實現信號量(Semaphores)的操作,以保證不會同時訪問公用的數據結構。

(4)單寄存器的 Load/Store 指令,這種指令用於把單一的數據傳入或者傳出一個寄存器。支持的數據類型有字節(8 位)、半字(16 位)和字(32 位)。

02. 單寄存器的Load/Store指令

如表 3-8 所示列出了所有單寄存器的 Load/Store 指令。
在這裏插入圖片描述

2.1 LDR 指令

LDR 指令用於從內存中將一個 32 位的字讀取到目標寄存器。

(1) 指令的語法格式

LDR{<cond>} <Rd>,<addr_mode>

(2) 應用示例

LDR R1,[R0,#0x12] ;將 R0+12 地址處的數據讀出,保存到 R1 中(R0 的值不變)

LDR R1,[R0]  ;將 R0 地址處的數據讀出,保存到 R1 中(零偏移)

LDR R1,[R0,R2] ;將 R0+R2 地址的數據讀出,保存到 R1 中(R0 的值不變)

LDR R1,[R0,R2,LSL #2]  ;將 R0+R2×4 地址處的數據讀出,保存到 R1 中(R0、R2 的值不變)

LDR Rd,label  ;label 爲程序標號,label 必須是當前指令的-4~4KB 範圍內

LDR Rd,[Rn],#0x04 ;Rn 的值用作傳輸數據的存儲地址。在數據傳送後,將偏移量 0x04 與 Rn 相加,
		    #結果寫回到 Rn 中。Rn 不允許是 R15

2.2 STR 指令

STR 指令用於將一個 32 位的字數據寫入到指令中指定的內存單元。

(1) 指令的語法格式

STR{<cond>} <Rd>,<addr_mode>

(2) 應用示例

LDR/STR 指令用於對內存變量的訪問、內存緩衝區數據的訪問、查表、外圍部件的控制操作等,若使用 LDR 指令加載數據到 PC 寄存器,則實現程序跳轉功能,這樣也就實現了程序散轉。

① 變量訪問。

NumCount .equ 0x40003000  ;定義變量 NumCount
LDR R0,=NumCount  ;使用 LDR 僞指令裝載 NumCount 的地址到 R0
LDR R1,[R0]  ;取出變量值
ADD R1,R1,#1  ;NumCount=NumCount+1
STR R1,[R0]  ;保存變量

② GPIO 設置。

GPIO—BASE .equ 0xe0028000 ;定義 GPIO 寄存器的基地址
…
LDR R0,=GPIO—BASE
LDR R1,=0x00ffff00  ;將設置值放入寄存器
STR R1,[R0,#0x0C] ;IODIR=0x00ffff00,IOSET 的地址爲 0xE0028004

③ 程序散轉。

…
MOV R2,R2,LSL #2  ;功能號乘以 4,以便查表
LDR PC,[PC,R2] ;查表取得對應功能子程序地址並跳轉
NOP
FUN—TAB .word FUN—SUB0
.word FUN—SUB1
.word FUN—SUB2
…

2.3 LDRB 指令

LDRB 指令根據 addr_mode 所確定的地址模式將一個 8 位字節讀取到指令中的目標寄存器 Rd。

指令的語法格式

LDR{<cond>}B <Rd>, <addr_mode>

2.4 STRB 指令

STRB 指令從寄存器中取出指定的 8 位字節放入寄存器的低 8 位,並將寄存器的高位補 0。

指令的語法格式

STR{<cond>}B <Rd>,<addr_mode>

2.5 LDRH 指令

LDRH 指令用於從內存中將一個 16 位的半字讀取到目標寄存器。如果指令的內存地址不是半字節對齊的,指令的執行結果不可預知。

指令的語法格式

LDR{<cond>}H <Rd>,<addr_mode>

2.6 STRH 指令

STRH 指令從寄存器中取出指定的 16 位半字放入寄存器的低 16 位,並將寄存器的高位補 0。

指令的語法格式

STR{<cond>}H <Rd>,<addr_mode>

03. 多寄存器的Load/Store內存訪問指令

多寄存器的 Load/Store 內存訪問指令又稱批量加載/存儲指令,它可以實現在一組寄存器和一塊連續的內存單元之間傳送數據。LDM 用於加載多個寄存器,STM 用於存儲多個寄存器。多寄存器的 Load/Store 內存訪問指令允許一條指令傳送 16 個寄存器的任何子集或所有寄存器。多寄存器的 Load/Store 內存訪問指令主要用於現場保護、數據複製和參數傳遞等。

如下表所示列出了多寄存器的 Load/Store 內存訪問指令。
在這裏插入圖片描述

3.1 LDM 指令

LDM 指令將數據從連續的內存單元中讀取到指令中指定的寄存器列表中的各寄存器中。當 PC 包含在 LDM 指令的寄存器列表中時,指令從內存中讀取的字數據將被作爲目標地址值,指令執行後程序將從目標地址處開始執行,從而實現了指令的跳轉。

指令的語法格式

LDM{<cond>}<addressing_mode> <Rn>{!}, <registers>

寄存器 R0~R15 分別對應於指令編碼中 bit[0]~bit[15]位。如果 Ri 存在於寄存器列表中,則相應的位等於 1,否則爲 0。LDM 指令將數據從連續的內存單元中讀取到指令中指定的寄存器列表中的各寄存器中。

指令的語法格式

LDM{<cond>}<addressing_mode><Rn>,<registers_without_pc>

3.2 STM 指令

STM 指令將指令中寄存器列表中的各寄存器數值寫入到連續的內存單元中。主要用於塊數據的寫入、數據棧操作及進入子程序時保存相關寄存器的操作。

指令的語法格式

STM{<cond>}<addressing_mode> <Rn>{!}, <registers>

STM 指令將指令中寄存器列表中的各寄存器數值寫入到連續的內存單元中。主要用於塊數據的寫入、數據棧操作及進入子程序時保存相關寄存器等操作。

指令的語法格式

STM{<cond>}<addressing_mode> <Rn>, <registers >ˆ

3.3 數據傳送指令應用

LDM/STM 批量加載/存儲指令可以實現在一組寄存器和一塊連續的內存單元之間傳輸數據。LDM 爲加載多個寄存器,STM 爲存儲多個寄存器。允許一條指令傳送 16 個寄存器的任何子集或所有寄存器。

指令格式如下

LDM{cond}<模式> Rn{!},regist{ˆ}
STM{cond}<模式> Rn{!},regist{ˆ}

LDM/STM 的主要用途有現場保護、數據複製和參數傳遞等。其模式有 8 種,其中前 4種用於數據塊的傳輸,後 4 種是堆棧操作,如下所示。

(1)IA:每次傳送後地址加 4。
(2)IB:每次傳送前地址加 4。
(3)DA:每次傳送後地址減 4。
(4)DB:每次傳送前地址減 4。
(5)FD:滿遞減堆棧。
(6)ED:空遞增堆棧。
(7)FA:滿遞增堆棧。
(8)EA:空遞增堆棧。

其中,寄存器 Rn 爲基址寄存器,裝有傳送數據的初始地址,Rn 不允許爲 R15;後綴“!”表示最後的地址寫回到 Rn 中;寄存器列表 reglist 可包含多於一個寄存器或寄存器範圍,使用“,”分開,如{R1,R2,R6~R9},寄存器排列由小到大排列;“ˆ”後綴不允許在用戶模式下使用,只能在系統模式下使用。若在 LDM 指令用寄存器列表中包含有 PC 時使用,那麼除了正常的多寄存器傳送外,將 SPSR 複製到 CPSR 中,這可用於異常處理返回;使用“ˆ”後綴進行數據傳送且寄存器列表不包含 PC 時,加載/存儲的是用戶模式寄存器,而不是當前模式寄存器。

LDMIA R0!,{R3~R9} ;加載 R0 指向的地址上的多字數據,保存到 R3~R9 中,R0 值更新
STMIA R1!,{R3~R9} ;將 R3~R9 的數據存儲到 R1 指向的地址上,R1 值更新
STMFD SP!,{R0~R7,LR}  ;現場保存,將 R0~R7、LR 入棧
LDMFD SP!,{R0~R7,PC}ˆ  ;恢復現場,異常處理返回

在進行數據複製時,先設置好源數據指針,然後使用塊複製尋址指令 LDMIA/STMIA、LDMIB/STMIB、LDMDA/STMDA、LDMDB/STMDB 進行讀取和存儲。而進行堆棧操作時,則要先設置堆棧指針,一般使用 SP,然後使用堆棧尋址指令 STMFD/LDMFD、
STMED/LDMED、STMEA/LDMEA 實現堆棧操作。數據是存儲在基址寄存器的地址之上還是之下,地址是存儲第一個值之前還是之後、增加還是減少,如下表所示。
在這裏插入圖片描述

應用示例一 使用 LDM/STM 進行數據複製

LDR R0,=SrcData  ;設置源數據地址
LDR R1,=DstData  ;設置目標地址
LDMIA R0,{R2~R9} ;加載 8 字數據到寄存器 R2~R9
STMIA R1,{R2~R9} ;存儲寄存器 R2~R9 到目標地址

應用示例二 使用 LDM/STM 進行現場寄存器保護,常在子程序或異常處理使用

SENDBYTE:
STMFD SP!,{R0~R7,LR} ;寄存器壓棧保護
…
BL DELAY ;調用 DELAY 子程序
…
LDMFD SP!,{R0~R7,PC} ;恢復寄存器,並返回

04. 單數據交換指令

交換指令是 Load/Store 指令的一種特例,它把一個寄存器單元的內容與寄存器內容交換。交換指令是一個原子操作(Atomic Operation),也就是說,在連續的總線操作中讀/寫一個存儲單元,在操作期間阻止其他任何指令對該存儲單元的讀/寫。

交換指令如下表所示。
在這裏插入圖片描述

4.1 SWP 字交換指令

SWP 指令用於將內存中的一個字單元和一個指定寄存器的值相交換。操作過程如下:假設內存單元地址存放在寄存器中,指令將中的數據讀取到目的寄存器 Rd 中,同時將另一個寄存器的內容寫入到該內存單元中。當和爲同一個寄存器時,指令交換該寄存器和內存單元的內容。

指令的語法格式

SWP{<cond>} <Rd>,<Rm>,[<Rn>]

4.2 SWPB 字節交換指令

SWPB 指令用於將內存中的一個字節單元和一個指定寄存器的低 8 位值相交換,操作過程如下:假設內存單元地址存放在寄存器中,指令將中的數據讀取到目的寄存器 Rd 中,寄存器 Rd 的高 24 位設爲 0,同時將另一個寄存器的低 8 位內容寫入到該內存字節單元中。當和爲同一個寄存器時,指令交換該寄存器低 8 位內容和內存字節單元的內容。

指令的語法格式

SWP{<cond>}B <Rd>,<Rm>,[<Rn>]

4.3 交換指令 SWP 應用

SWP 指令用於將一個內存單元(該單元地址放在寄存器 Rn 中)的內容讀取到一個寄存器 Rd 中,同時將另一個寄存器 Rm 的內容寫到該內存單元中,使用 SWP 可實現信號量操作。

指令的語法格式

SWP{cond}B Rd,Rm,[Rn]

其中,B 爲可選後綴,若有 B,則交換字節;否則交換 32 位字。Rd 爲目的寄存器,存儲從存儲器中加載的數據,同時,Rm 中的數據將會被存儲到存儲器中。若 Rm 與 Rn 相同,則爲寄存器與存儲器內容進行交換。Rn 爲要進行數據交換的存儲器地址,Rn 不能與Rd 和 Rm 相同。

SWP 指令舉例

SWP R1,R1,[R0] ;將 R1 的內容與 R0 指向的存儲單元內容進行交換
SWPB R1,R2,[R0]  ;將 R0 指向的存儲單元內容讀取一字節數據到 R1 中(高 24 位清零), 並將 R2 的內容
寫入到該內存單元中(最低字節有效),使用 SWP 指令可以方便地進行信號量操作
12C_SEM .equ 0x40003000
…
12C_SEM_WAIT:
MOV R0,#0
LDR R0,=12C_SEM
SWP R1,R1,[R0]  ;取出信號量,並將其設爲 0
CMP R1,#0  ;判斷是否有信號
BEQ 12C_SEM_WAIT ;若沒有信號則等待

05. 附錄

5.1 ARM Architecture Reference Manual

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