?
5.4? 多寄存器Load/Store內(nèi)存訪問(wèn)指令
多寄存器Load/Store內(nèi)存訪問(wèn)指令也叫批量加載/存儲(chǔ)指令,它可以實(shí)現(xiàn)在一組寄存器和一塊連續(xù)的內(nèi)存單元之間傳送數(shù)據(jù)。LDM用于加載多個(gè)寄存器,STM用于存儲(chǔ)多個(gè)寄存器。多寄存器Load/Store內(nèi)存訪問(wèn)指令允許一條指令傳送16個(gè)寄存器的任何子集或所有寄存器。
多寄存器Load/Store內(nèi)存訪問(wèn)指令主要用于現(xiàn)場(chǎng)保護(hù)、數(shù)據(jù)復(fù)制和參數(shù)傳遞等。
注意 |
多寄存器Load/Store內(nèi)存訪問(wèn)指令會(huì)增加中斷延時(shí),因?yàn)锳RM通常不會(huì)打斷正在執(zhí)行的指令去響應(yīng)中斷,而必須等到指令執(zhí)行完。也就是說(shuō),如果一個(gè)中斷在多寄存器Load/Store內(nèi)存訪問(wèn)指令執(zhí)行期間產(chǎn)生,那么處理器在多寄存器Load/Store內(nèi)存訪問(wèn)指令執(zhí)行完后才對(duì)中斷響應(yīng)。 |
表5.2總結(jié)了多寄存器Load/Store內(nèi)存訪問(wèn)指令
表5.2???? 多寄存器Load/Store內(nèi)存訪問(wèn)指令
指??? 令 |
作??? 用 |
操??? 作 |
LDM |
裝載多個(gè)寄存器 |
{Rd}*N←mem32[start address+4*N] |
STM |
保存多個(gè)寄存器 |
{Rd}*N→mem32[start address+4*N] |
5.4.1? 多寄存器內(nèi)存字?jǐn)?shù)據(jù)傳送指令
1.LDM(1)指令
(1)指令編碼格式
LDM(1)指令將數(shù)據(jù)從連續(xù)的內(nèi)存單元中讀取到指令中指定的寄存器列表中的各寄存器中。
當(dāng)PC包含在LDM指令的寄存器列表中時(shí),指令從內(nèi)存中讀取的字?jǐn)?shù)據(jù)將被作為目標(biāo)地址值,指令執(zhí)行后程序?qū)哪繕?biāo)地址處開(kāi)始執(zhí)行,從而實(shí)現(xiàn)了指令的跳轉(zhuǎn)。
指令的編碼格式如圖5.15所示。
圖5.15? LDM(1)指令編碼格式
(2)指令的語(yǔ)法格式
LDM{<cond>}<addressing_mode>? <Rn>{!},? <registers>
① <cond>
為指令編碼中的條件域。它指示LDM(1)指令在什么條件下執(zhí)行。當(dāng)<cond>忽略時(shí),指令為無(wú)條件執(zhí)行(cond=AL(Alway))。
② <address_mode>
指令的尋址方式。確定編碼格式中的P、U和W位。
③ <Rn>
確定尋址模式所使用的基址寄存器。
如果r15作為指令的基址寄存器,指令的執(zhí)行結(jié)果不可預(yù)知。
④ !
設(shè)置指令編碼格式中的W位。它使指令執(zhí)行后將操作數(shù)的內(nèi)存地址寫(xiě)入基址寄存器<Rn>中;如果!被忽略,W位為0,指令執(zhí)行完后,不修改基址寄存器的值。
注意 |
如果基址寄存器包含在指令列表中,當(dāng)指令執(zhí)行完后,基址寄存器的值是新加載進(jìn)的特定內(nèi)存地址的值。也就是說(shuō),即使指令沒(méi)有出現(xiàn)在指令列表中,基址寄存器的值也可能被修改。 |
⑤ <registers>
被加載的寄存器列表。不同的寄存器之間用“,”隔開(kāi)。完整的寄存器列表包含在“{}”中。編號(hào)低的寄存器對(duì)應(yīng)于內(nèi)存中低地址單元,編號(hào)高的寄存器對(duì)應(yīng)于內(nèi)存中高地址單元。
注意 |
無(wú)論寄存器在寄存器列表“{}”中如何排列,都將遵循上述規(guī)則。 |
寄存器r0~r15分別對(duì)應(yīng)于指令編碼中bit[0]~bit[15]位。如果Ri存在于寄存器列表中,則相應(yīng)的位等于1,否則為0。
?
(3)指令操作的偽代碼
指令操作偽代碼如下面程序段所示。
If? ConditionPass{cond}? then
???? Address=start_address
???? For? i=0? to 14
???????? If? register_list[i]==1? then
???????????? Ri=Memory[address,4]
???????????? Address=address+4
???? If? register_list[15]==1? then
?????????????? Value = Memory[address,4]
?????????????? If(architecture version 5 or above)? then
???????????????????? Pc= value? AND? 0xfffffffe
???????????????????? T bit=value[0]
?????????????? Else
?????????????? ??????Pc= value? AND? 0xfffffffc
?????????????? Address=address+4
???? Assert end_address=address+4
2.STM(1)指令
(1)指令編碼格式
STM(1)指令將指令中寄存器列表中的各寄存器數(shù)值寫(xiě)入到連續(xù)的內(nèi)存單元中。主要用于塊數(shù)據(jù)的寫(xiě)入、數(shù)據(jù)棧操作以及進(jìn)入子程序時(shí)保存相關(guān)寄存器的操作。
指令編碼格式如圖5.16所示。
圖5.16? STM(1)指令編碼格式
(2)指令的語(yǔ)法格式
STM{<cond>}<addressing_mode>? <Rn>{!},? <registers>
① <cond>
為指令編碼中的條件域。它指示STM(1)指令在什么條件下執(zhí)行。當(dāng)<cond>忽略時(shí),指令為無(wú)條件執(zhí)行(cond=AL(Alway))。
② <address_mode>
指令的尋址方式。確定編碼格式中的P、U和W位。
③ <Rn>
確定尋址模式所使用的基址寄存器。
如果r15作為指令的基址寄存器,指令的執(zhí)行結(jié)果不可預(yù)知。
④ !
設(shè)置指令編碼格式中的W位。它使指令執(zhí)行后將操作數(shù)的內(nèi)存地址寫(xiě)入基址寄存器<Rn>中;如果!被忽略,W位為0,指令執(zhí)行完后,不修改基址寄存器的值。
⑤ <registers>
被加載的寄存器列表。不同的寄存器之間用“,”隔開(kāi)。完整的寄存器列表包含在“{}”中。編號(hào)低的寄存器對(duì)應(yīng)于內(nèi)存中低地址單元,編號(hào)高的寄存器對(duì)應(yīng)于內(nèi)存中高地址單元。
寄存器r0~r15分別對(duì)應(yīng)于指令編碼中bit[0]~bit[15]位。如果Ri存在于寄存器列表中,則相應(yīng)的位等于1,否則為0。
(3)指令操作的偽代碼
指令操作偽代碼如下面程序段所示。
If? ConditionPassed{cond}? then
???? Address=Start_address
???? For? i=0? to? 15
?????????? If? register_list[i]==1
?????????? Memory[address,4]=Ri
?????????? Address=address+4
???? Assert? end_address==address-4
?
5.4.2? 用戶(hù)模式多寄存器內(nèi)存字?jǐn)?shù)據(jù)傳送指令
1.LDM(2)指令
(1)指令編碼格式
LDM(2)指令將數(shù)據(jù)從連續(xù)的內(nèi)存單元中讀取到指令中指定的寄存器列表中的各寄存器中。
注意 |
與LDM(1)指令不同,PC不能包含在寄存器列表中。 |
指令的編碼格式如圖5.17所示。
圖5.17? LDM(2)指令編碼格式
(2)指令的語(yǔ)法格式
LDM{<cond>}<addressing_mode>? <Rn>,? <registers_without_pc>??
① <cond>
為指令編碼中的條件域。它指示LDM(2)指令在什么條件下執(zhí)行。當(dāng)<cond>忽略時(shí),指令為無(wú)條件執(zhí)行(cond=AL(Alway))。
② <address_mode>
指令的尋址方式。確定編碼格式中的P位和U位。此指令中W位指定為0。
③ <Rn>
確定尋址模式所使用的基址寄存器。
如果r15作為指令的基址寄存器,指令的執(zhí)行結(jié)果不可預(yù)知。
④ <registers_without_pc>?
被加載的寄存器列表。不同的寄存器之間用“,”隔開(kāi)。完整的寄存器列表包含在“{}”中。此寄存器列表中不能包含PC寄存器。
如果PC包含在寄存器列表中,指令的執(zhí)行結(jié)果不可預(yù)知。
其他細(xì)節(jié)可參考LDM(1)指令。
(3)指令操作的偽代碼
指令操作偽代碼如下面程序段所示。
If? ConditionPassed{cond}? then
???? Address=start_address
???? For? i=0? to? 14
????????? If? register_list[i]==1
??????????????? Ri_usr=Memory[address,4]
??????????????? Address=address+4
???? Assert? end_address == address-4
2.STM(2)指令
(1)指令編碼格式
STM(2)指令將指令中寄存器列表中的各寄存器數(shù)值寫(xiě)入到連續(xù)的內(nèi)存單元中。主要用于塊數(shù)據(jù)的寫(xiě)入、數(shù)據(jù)棧操作以及進(jìn)入子程序時(shí)保存相關(guān)寄存器等操作。
指令編碼格式如圖5.18所示。
圖5.18? STM(2)指令編碼格式
(2)指令的語(yǔ)法格式
STM{<cond>}<addressing_mode>? <Rn>,? <registers >?
① <cond>
為指令編碼中的條件域。它指示LDM(2)指令在什么條件下執(zhí)行。當(dāng)<cond>忽略時(shí),指令為無(wú)條件執(zhí)行(cond=AL(Alway))。
② <address_mode>
指令的尋址方式。確定編碼格式中的P位和U位。此指令中W位指定為0。
③ <Rn>
確定尋址模式所使用的基址寄存器。
如果r15作為指令的基址寄存器,指令的執(zhí)行結(jié)果不可預(yù)知。
④ <registers >?
寄存器列表。只能使用用戶(hù)模式下的寄存器。
(3)指令操作的偽代碼
指令操作偽代碼如下面程序段所示。
If? ConditionPassed{cond}? then
???? Address=start_address
???? For? i=0? to? 15
?????????? If? register_list[i] == 1
???????????????? Memory[address,4]=Ri_usr
???????????????? Address = address +4
????? Assert? end_address == address-4
?
5.4.3? 帶狀態(tài)寄存器的多寄存器內(nèi)存字?jǐn)?shù)據(jù)裝載指令(LDM(3))
(1)指令編碼格式
LDM(3)指令將數(shù)據(jù)從連續(xù)的內(nèi)存單元中讀取數(shù)據(jù)到寄存器列表中的各寄存器中。它同時(shí)將當(dāng)前處理器模式對(duì)應(yīng)的SPSR寄存器的內(nèi)容復(fù)制到CPSR寄存器中。
當(dāng)PC包含在LDM指令的寄存器列表中時(shí),指令從內(nèi)存中讀取的數(shù)據(jù)將被作為目標(biāo)地址值,指令執(zhí)行后程序?qū)哪繕?biāo)地址處開(kāi)始執(zhí)行,從而實(shí)現(xiàn)了指令的跳轉(zhuǎn)。
在ARM v5及以上的版本和T系列的ARM v4版本中,SPSR寄存器的T位將復(fù)制到CPSR寄存器的T位,該位決定目標(biāo)地址處的程序狀態(tài)。在以前的版本中程序繼續(xù)執(zhí)行在ARM狀態(tài)。
指令的編碼格式如圖5.19所示。
圖5.19? LDM(3)指令編碼格式
(2)指令的語(yǔ)法格式
LDM{<cond>}<addressing_mode>? <Rn>{!},? <registers_and_pc>?
① <cond>
為指令編碼中的條件域。它指示LDM(1)指令在什么條件下執(zhí)行。當(dāng)<cond>忽略時(shí),指令為無(wú)條件執(zhí)行(cond=AL(Alway))。
② <address_mode>
指令的尋址方式。確定編碼格式中的P、U和W位。
③ <Rn>
確定尋址模式所使用的基址寄存器。
如果r15作為指令的基址寄存器,指令的執(zhí)行結(jié)果不可預(yù)知。
④ !
設(shè)置指令編碼格式中的W位。它使指令執(zhí)行后將操作數(shù)的內(nèi)存地址寫(xiě)入基址寄存器<Rn>中;如果!被忽略,W位為0,指令執(zhí)行完后,不修改基址寄存器的值。
注意 |
如果基址寄存器包含在指令列表中,當(dāng)指令執(zhí)行完后,基址寄存器的值是新加載進(jìn)的特定內(nèi)存地址的值。也就是說(shuō),即使指令沒(méi)有出現(xiàn)在指令列表中,基址寄存器的值也可能被修改。 |
⑤ <registers_and_pc>?
寄存器列表。
注意 |
在本格式的指令中寄存器列表中必須包含PC寄存器。 |
被加載的寄存器列表。不同的寄存器之間用“,”隔開(kāi)。完整的寄存器列表包含在“{}”中。編號(hào)低的寄存器對(duì)應(yīng)于內(nèi)存中的低地址單元,編號(hào)高的寄存器對(duì)應(yīng)于內(nèi)存中的高地址單元。
寄存器r0~r15分別對(duì)應(yīng)于指令編碼中bit[0]~bit[15]位。如果Ri存在于寄存器列表中,則相應(yīng)的位等于1,否則為0。
該指令執(zhí)行時(shí)將當(dāng)前處理器模式下的SPSR值復(fù)制到CPSR中。指令的其他參數(shù)可參見(jiàn)LDM(1)指令格式。
(3)指令操作的偽代碼
指令操作偽代碼如下面程序段所示。
If? ConditionPass{<cond>}? then
???? Address=start_address
???? For i=0? to? 14
?????????? If? register_list[i]==1 then
???????????????? Ri=Memory[address,4]
???????????????? Address=address+4
???? CPSR=SPSR
???? Value=memory[address,4]
???? If {architecture version 4T, 5 or above} and {T bit ==1} then
???? Else
?????????? Pc=value AND oxfffffffc
???? Address=address + 4
???? Assert end_address=address-4
?
5.4.4? 數(shù)據(jù)傳送指令應(yīng)用
LDM/STM批量加載/存儲(chǔ)指令可以實(shí)現(xiàn)在一組寄存器和一塊連續(xù)的內(nèi)存單元之間傳輸數(shù)據(jù)。LDM為加載多個(gè)寄存器,STM為存儲(chǔ)多個(gè)寄存器。允許一條指令傳送16個(gè)寄存器的任何子集或所有寄存器。指令格式如下:
LDM{cond}<模式>? Rn{!},regist{?}
STM{cond}<模式>? Rn{!},regist{?}
LDM/STM的主要用途有現(xiàn)場(chǎng)保護(hù)、數(shù)據(jù)復(fù)制和參數(shù)傳遞等。其模式有8種,如下所示。
前面4種用于數(shù)據(jù)塊的傳輸,后面4種是堆棧操作。
(1)IA:每次傳送后地址加4。
(2)IB:每次傳送前地址加4。
(3)DA:每次傳送后地址減4。
(4)DB:每次傳送前地址減4。
(5)FD:滿遞減堆棧。
(6)ED:空遞增堆棧。
(7)FA:滿遞增堆棧。
(8)EA:空遞增堆棧。
其中,寄存器Rn為基址寄存器,裝有傳送數(shù)據(jù)的初始地址,Rn不允許為R15;后綴“!”表示最后的地址寫(xiě)回到Rn中;寄存器列表reglist可包含多于一個(gè)寄存器或寄存器范圍,使用“,”分開(kāi),如{R1,R2,R6~R9},寄存器排列由小到大排列;“?”后綴不允許在用戶(hù)模式下,只能在系統(tǒng)模式下使用。若在LDM指令用寄存器列表中包含有PC時(shí)使用,那么除了正常的多寄存器傳送外,將SPSR拷貝到CPSR中,這可用于異常處理返回;使用“?”后綴進(jìn)行數(shù)據(jù)傳送且寄存器列表不包含PC時(shí),加載/存儲(chǔ)的是用戶(hù)模式寄存器,而不是當(dāng)前模式寄存器。
注意 |
地址對(duì)齊問(wèn)題,在這些指令中,忽略地址位[1:0]。 批量加載/存儲(chǔ)指令舉例如下。 |
LDMIA? r0!,{r3~r9}????????? ;加載r0指向的地址上的多字?jǐn)?shù)據(jù),保存到r3~r9中,r0值更新
STMIA? r1!,{r3~r9}???????? ;將r3~r9的數(shù)據(jù)存儲(chǔ)到r1指向的地址上,r1值更新
STMFD? SP!,{r0~r7,LR}?????? ;現(xiàn)場(chǎng)保存,將r0~r7、LR入棧
LDMFD? SP!,{r0~r7,PC}????? ;恢復(fù)現(xiàn)場(chǎng),異常處理返回
在進(jìn)行數(shù)據(jù)復(fù)制時(shí),先設(shè)置好源數(shù)據(jù)指針,然后使用塊拷貝尋址指令LDMIA/STMIA、LDMIB/STMIB、LDMDA/STMDA、LDMDB/STMDB進(jìn)行讀取和存儲(chǔ)。而進(jìn)行堆棧操作時(shí),則要先設(shè)置堆棧指針,一般使用SP然后使用堆棧尋址指令STMFD/LDMFD、STMED/LDMED、STMEA/LDMEA實(shí)現(xiàn)堆棧操作。
多寄存器傳送指令如例5.3所示。其中r1為指令執(zhí)行前的基址寄存器,r1’則為指令執(zhí)行后的基址寄存器。
【例5.3】多寄存器傳送指令示意。
(1)STMIA? r1,{r5~r7}
(2)STMIB? r1!,{r5~r7}
(3)STMDA? r1!,{r5~r7}
(4)STMDB? r1!,{r5~r7}
數(shù)據(jù)是存儲(chǔ)在基址寄存器的地址之上還是之下,地址是存儲(chǔ)第一個(gè)值之前還是之后、增加還是減少,如表5.3所示。
表5.3 多寄存器Load/Store內(nèi)存訪問(wèn)指令映射
向 上 生 長(zhǎng) |
向 下 生 長(zhǎng) |
||||
滿 |
空 |
滿 |
空 |
||
增加 |
之前 |
STMIB |
LDMIB |
||
STMFA |
LDMED |
||||
之后 |
STMIA |
LDMIA |
|||
STMEA |
LDMFD |
||||
增加 |
之前 |
LDMDB |
STMDB |
||
LDMEA |
STMFD |
||||
之后 |
LDMDA |
STMDA |
|||
LDMFA |
STMED |
【例5.4】使用LDM/STM進(jìn)行數(shù)據(jù)復(fù)制。
LDR? r0,=SrcData?????????? ;設(shè)置源數(shù)據(jù)地址
LDR? r1,=DstData?????????? ;設(shè)置目標(biāo)地址
LDMIA?? r0,{r2~r9}??????? ;加載8字?jǐn)?shù)據(jù)到寄存器r2~r9
STMIA ??r1,{r2~r9}??????? ;存儲(chǔ)寄存器r2~r9到目標(biāo)地址
【例5.5】使用LDM/STM進(jìn)行現(xiàn)場(chǎng)寄存器保護(hù),常在子程序或異常處理使用。
SENDBYTE
????? STMFD???? SP!,{r0~r7,LR}??????? ;寄存器壓棧保護(hù)
?? …….
????? BL??????? DELAY????????????????? ;調(diào)用DELAY子程序
?? …….
????? LDMFD???? SP!,{r0~r7,PC}??????? ;恢復(fù)寄存器,并返回