在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

零基礎(chǔ)學(xué)ARM:程序狀態(tài)寄存器訪問指令解析

電子設(shè)計(jì) ? 來源:電子設(shè)計(jì) ? 作者:電子設(shè)計(jì) ? 2020-12-24 13:36 ? 次閱讀

一、程序狀態(tài)寄存器訪問指令

ARM微處理器支持程序狀態(tài)寄存器訪問指令,用于在程序狀態(tài)寄存器和通用寄存器之間傳送數(shù)據(jù)。

MRSMRS{條件} 通用寄存器,程序狀態(tài)寄存器(CPSR或SPSR)

MRS指令用于將程序狀態(tài)寄存器的內(nèi)容傳送到通用寄存器中。該指令一般用在以下幾種情況:

當(dāng)需要改變程序狀態(tài)寄存器的內(nèi)容時(shí),可用MRS將程序狀態(tài)寄存器的內(nèi)容讀入通用寄存器,修改后再寫回程序狀態(tài)寄存器。當(dāng)在異常處理或進(jìn)程切換時(shí),需要保存程序狀態(tài)寄存器的值,可先用該指令讀出程序狀態(tài)寄存器的值,然后保存。如:MRS R0,CPSR ;傳送CPSR的內(nèi)容到R0
MRS R0,SPSR ;傳送SPSR的內(nèi)容到R0
MSRMSR{條件} 程序狀態(tài)寄存器(CPSR或SPSR)_<域>,操作數(shù)

MSR指令用于將操作數(shù)的內(nèi)容傳送到程序狀態(tài)寄存器的特定域中。其中,操作數(shù)可以為通用寄存器或立即數(shù)。<域>用于設(shè)置程序狀態(tài)寄存器中需要操作的位,32位的程序狀態(tài)寄存器可分為4個(gè)域:

位[31:24]為條件標(biāo)志位域,用f表示;

位[23:16]為狀態(tài)位域,用s表示;

位[15:8]為擴(kuò)展位域,用x表示;

位[7:0]為控制位域,用c表示;

該指令通常用于恢復(fù)或改變程序狀態(tài)寄存器的內(nèi)容,在使用時(shí),一般要在MSR指令中指明將要操作的域。如:

MSR CPSR,R0 ;傳送R0的內(nèi)容到CPSR

MSR SPSR,R0 ;傳送R0的內(nèi)容到SPSR

MSR CPSR_c,R0 ;傳送R0的內(nèi)容到SPSR,但僅僅修改CPSR中的控制位域
應(yīng)用舉例使能中斷

要是能中斷,必須將寄存器CPSR的bit[7]設(shè)置為0

要將寄存器CPSR的bit[7]設(shè)置為0,但是不能影響其他位,所以必須先用msr讀取出cpsr的值到通用寄存器Rn(n取值0~8),然后修改bit[7]設(shè)置為0,再將該寄存器的值設(shè)置到CPSR中。

代碼如下:

area reset,code
code32
entry
start
bl enale_irq
enale_irq
mrs r0,cpsr
bic r0,r0,#0x80
msr cpsr_c,r0
mov pc,lr

執(zhí)行結(jié)果:

第8行【其實(shí)第8行還沒有執(zhí)行】:

當(dāng)前模式時(shí)SVC ,因?yàn)殚_機(jī)商店屬于reset異常,而該異常會(huì)自動(dòng)進(jìn)入svc模式CPSR的值是0X000000D39行

mrs r0,cpsr 將cpsr的內(nèi)容讀取到寄存器r0中R0的值為0X000000D310行

bic r0,r0,#0x80 將r0的第7個(gè)bit位置設(shè)置為0(從低往高數(shù),0開始計(jì)數(shù))寄存器R0的值變成0x0000005311行

msr cpsr_c,r0 將構(gòu)造好的值寫回CPSR,此時(shí)CPSR的I 位已經(jīng)為0從而實(shí)現(xiàn)了中斷使能禁止中斷同理,我們要關(guān)閉中斷,只需要將CPSR的I位設(shè)置為1即可。 area reset,code
code32
entry
start
bl diable_irq
diable_irq
mrs r0,cpsr
orr r0,r0,#0x80
msr cpsr_c,r0
mov pc,lr
end
設(shè)置各模式的棧地址要想初始化各個(gè)模式的棧地址,必須首先切換到對(duì)應(yīng)的模式,然后再將棧地址設(shè)置到寄存器sp即可。

代碼:

area reset,code
code32
entry
start
bl stack_init
stack_init ; 棧指針初始化函數(shù)
; @undefine_stack
msr cpsr_c,#0xdb ; 切換到未定義異常
ldr sp,=0x34000000 ; 棧指針為內(nèi)存最高地址,棧為倒生的棧
; 棧空間的最后1M 0x34000000~0x33f00000
; @abort_stack
msr cpsr_c,#0xd7 ; 切換到終止異常模式
ldr sp,=0x33f00000 ; ??臻g為1M,0x33f00000~0x33e00000
; @irq_stack
msr cpsr_c,#0xd2 ; 切換到中斷模式
ldr sp,=0x33e00000 ; 棧空間為1M,0x33e00000~0x33d00000
; @ sys_stack
msr cpsr_c,#0xdf ; 切換到系統(tǒng)模式
ldr sp,=0x33d00000 ; 棧空間為1M,0x33d00000~0x33c00000
msr cpsr_c,#0xd3 ; 切換回管理模式
mov pc,lr
end

「結(jié)果分析:」我們只分析undef棧的初始化。

8行

模式切換前,當(dāng)前模式時(shí)svc模式,CPSR的值是0x000000D3注意看下SVC和undef模式的SP值都是09行

msr cpsr_c ,# 0xdb 直接對(duì)CPSR進(jìn)行賦值,將當(dāng)前模式設(shè)置為undef模式Current模式看到的LR寄存器值變成了0,因?yàn)槟J角袚Q成了undef模式,該模式下有自己的LR、SP寄存器SVC模式的私有寄存器SP和LR沒有改變12行

12行l(wèi)dr sp,=0x34000000 將常數(shù)裝載到寄存器sp中,(=表示這是一條偽指令)注意觀察,SVC模式的sp沒有變化,undef模式的SP被設(shè)置為 0x34000000

其他模式的棧初始化以此類推。

二、尋址方式

處理器根據(jù)指令中給出的地址信息來尋找物理地址的方式。

在講解尋址方式之前,我們首先來看下LDR、STR指令。

1. 加載存儲(chǔ)指令

ARM微處理器支持加載/存儲(chǔ)指令用于在寄存器和存儲(chǔ)器之間傳送數(shù)據(jù),加載指令用于將存儲(chǔ)器中的數(shù)據(jù)傳送到寄存器,存儲(chǔ)指令則完成相反的操作。

我們之前講的尋址方式都是直接對(duì)立即數(shù)或者寄存器尋址,如果我們想訪問外部存儲(chǔ)器的某個(gè)內(nèi)存地址或者一些外設(shè)的控制器寄存器該如何操作呢?

那就需要進(jìn)行寄存器間接尋址。如下圖所示,訪問外存需要通過AHB、APB總線,所以往往需要幾個(gè)指令周期才能實(shí)現(xiàn)1個(gè)數(shù)據(jù)的讀寫。

訪問外存LDR指令

LDR指令的格式為:

LDR{條件} 目的寄存器,<存儲(chǔ)器地址>
LDR指令用于從存儲(chǔ)器中將一個(gè)32位的字?jǐn)?shù)據(jù)傳送到目的寄存器中。

1) 用于從存儲(chǔ)器中讀取32位的字?jǐn)?shù)據(jù)到通用寄存器,然后對(duì)數(shù)據(jù)進(jìn)行處理。2) 當(dāng)程序計(jì)數(shù)器PC作為目的寄存器時(shí),指令從存儲(chǔ)器中讀取的字?jǐn)?shù)據(jù)被當(dāng)作目的地址,從而可以實(shí)現(xiàn)程序流程的跳轉(zhuǎn)。如:

LDR R0,[R1] ;將存儲(chǔ)器地址為R1的字?jǐn)?shù)據(jù)讀入寄存器R0。
LDR R0,[R1,R2] ;將存儲(chǔ)器地址為R1+R2的字?jǐn)?shù)據(jù)讀入寄存器R0。
LDR R0,[R1,#8] ;將存儲(chǔ)器地址為R1+8的字?jǐn)?shù)據(jù)讀入寄存器R0。
LDR R0,[R1,R2] ! ;將存儲(chǔ)器地址為R1+R2的字?jǐn)?shù)據(jù)讀入寄存器R0,并將
;新地址R1+R2寫入R1。
LDR R0,[R1,#8] ! ;將存儲(chǔ)器地址為R1+8的字?jǐn)?shù)據(jù)讀入寄存器R0,并將新
;地址R1+8寫入R1。
LDR R0,[R1],R2 ;將存儲(chǔ)器地址為R1的字?jǐn)?shù)據(jù)讀入寄存器R0,并將新地
;址R1+R2寫入R1。
LDR R0,[R1,R2,LSL#2]! ;將存儲(chǔ)器地址為R1+R2×4的字?jǐn)?shù)據(jù)讀入寄存器R0,
;并將新地址R1+R2×4寫入R1。
LDR R0,[R1],R2,LSL#2 ;將存儲(chǔ)器地址為R1的字?jǐn)?shù)據(jù)讀入寄存器R0,并將新地
;址R1+R2×4寫入R1。
STR指令

STR指令的格式為:STR{條件} 源寄存器,<存儲(chǔ)器地址>STR指令用于從源寄存器中將一個(gè)32位的字?jǐn)?shù)據(jù)傳送到存儲(chǔ)器中。該指令在程序設(shè)計(jì)中比較常用,且尋址方式靈活多樣,使用方式可參考指令LDR。如:

STR R0,[R1],#8 ;將R0中的字?jǐn)?shù)據(jù)寫入以R1為地址的存儲(chǔ)器中,并將新地址R1+8寫入R1。
STR R0,[R1,#8] ;將R0中的字?jǐn)?shù)據(jù)寫入以R1+8為地址的存儲(chǔ)器中。

LDR/STR指令都可以加B、H、SB、SH的后綴,分別表示加載/存儲(chǔ)字節(jié)、半字、帶符號(hào)的字節(jié)、帶符號(hào)的半字。如LDRB指令表示從存儲(chǔ)器加載一個(gè)字節(jié)進(jìn)寄存器。當(dāng)使用這些后綴時(shí),要注意所使用的存儲(chǔ)器要支持訪問的數(shù)據(jù)寬度。

LDRB指令

LDRB指令的格式為:

LDR{條件}B 目的寄存器,<存儲(chǔ)器地址>

LDRB指令用于從存儲(chǔ)器中將一個(gè)8位的字節(jié)數(shù)據(jù)傳送到目的寄存器中,同時(shí)將寄存器的高24位清零。該指令通常用于從存儲(chǔ)器中讀取8位的字節(jié)數(shù)據(jù)到通用寄存器,然后對(duì)數(shù)據(jù)進(jìn)行處理。

「指令示例:」

LDRB R0,[R1] ;將存儲(chǔ)器地址為R1的字節(jié)數(shù)據(jù)讀入寄存器R0,并將R0的高24位清零。
LDRB R0,[R1,#8];將存儲(chǔ)器地址為R1+8的字節(jié)數(shù)據(jù)讀入寄存器R0,并將R0的高24位清零。
LDRH指令

LDRH指令的格式為:

LDR{條件}H 目的寄存器,<存儲(chǔ)器地址>

LDRH指令用于從存儲(chǔ)器中將一個(gè)16位的半字?jǐn)?shù)據(jù)傳送到目的寄存器中,同時(shí)將寄存器的高16位清零。該指令通常用于從存儲(chǔ)器中讀取16位的半字?jǐn)?shù)據(jù)到通用寄存器,然后對(duì)數(shù)據(jù)進(jìn)行處理。

「指令示例:」

LDRH R0,[R1] ;將存儲(chǔ)器地址為R1的半字?jǐn)?shù)據(jù)讀入寄存器R0,并將R0的高16位清零。
LDRH R0,[R1,R2];將存儲(chǔ)器地址為R1+R2的半字?jǐn)?shù)據(jù)讀入寄存器R0,并將R0的高16位清零。
舉例1) STR r0,[r1,#12]

如上圖所示:

寄存器r0中的值是0x5,r1中的值是0x200將r1的值加上#12,得到地址0x20c將r0寄存器里的值發(fā)送給該地址對(duì)應(yīng)的內(nèi)存,即向地址0x20c中賦值0x52) STR r0,[r1],#12

如上圖所示:

寄存器r0的值是0x5,r1中的值是0x200將r0寄存器里的值發(fā)送給該r1中的值對(duì)應(yīng)的內(nèi)存,即向地址0x200中賦值0x5將r1的值加上#12并賦值給r1,r1的值就變成了0x20c

「擴(kuò)展:」比如有以下c代碼

int *ptr;
x = *ptr++;

經(jīng)過編譯器編譯,可以將這兩行代碼編譯為一條單指令:

LDR r0, [r1], #4
2. 立即尋址

立即尋址也叫立即數(shù)尋址,這是一種特殊的尋址方式,操作數(shù)本身就在指令中給出,只要取出指令也就取到了操作數(shù)。這個(gè)操作數(shù)被稱為立即數(shù),對(duì)應(yīng)的尋址方式也就叫做立即尋址。例如以下指令:

Add r0,r0,#1 ;R0=R0+1

在以上兩條指令中,第二個(gè)源操作數(shù)即為立即數(shù),要求以“?!睘榍熬Y,對(duì)于以十六進(jìn)制表示的立即數(shù),還要求在“#”后加上“0x”或“&”。

3. 寄存器尋址

利用寄存器中的數(shù)值作為操作數(shù),這種尋址方式是各類微處理器經(jīng)常采用的一種方式,也是一種執(zhí)行效率較高的尋址方式。

Add R0 , R1,R2 ;R0=R1+R2

該指令的執(zhí)行效果是將寄存器R1和R2的內(nèi)容相加,其結(jié)果存放在寄存器R0中。

4. 寄存器間接尋址

以寄存器中的值作為操作數(shù)的地址,而操作數(shù)本身存放在存儲(chǔ)器中。例如以下指令:

Add R0,R1,[R2] ; R0=R1+[R2]
LDR R0,[R1] ; R0=[R1]

在第一條指令中,以寄存器R2的值作為操作數(shù)的地址,在存儲(chǔ)器中取得一個(gè)操作數(shù)后與R1相加,結(jié)果存入寄存器R0中。第二條指令將以R1的值為地址的存儲(chǔ)器中的數(shù)據(jù)傳送到R0中。

5. 基址變址尋址

將寄存器(該寄存器一般稱作基址寄存器)的內(nèi)容與指令中給出的地址偏移量相加,從而得到一個(gè)操作數(shù)的有效地址:

LDR R0,[R1,#4] ;R0=[R1+4]
LDR R0,[R1,#4] ! ;R0=[R1+4]、R1=R1+4
LDR R0,[R1],#4 ;R0=[R1] 、R1=R1+4
LDR R0,[R1,R2] ;R0=[R1+R2]
6. 多寄存器尋址

采用多寄存器尋址方式,一條指令可以完成多個(gè)寄存器值的傳送。這尋址方式可以用一條指令完成傳送最多16個(gè)通用寄存器的值。以下指令:

LDMIA R0,{R1,R2,R3,R4} ;R1=[R0] R2=[R0+4] R3=[R0+8] R4=[R0+12]

該指令的后綴IA表示在每次執(zhí)行完加載/存儲(chǔ)操作后,R0按字長(zhǎng)度增加,因此,指令可將連續(xù)存儲(chǔ)單元的值傳送到R1~R4。

7. 相對(duì)尋址

與基址變址尋址方式相類似,相對(duì)尋址以程序計(jì)數(shù)器PC的當(dāng)前值為基地址,指令中的地址標(biāo)號(hào)作為偏移量,將兩者相加之后得到操作數(shù)的有效地址。以下程序段完成子程序的調(diào)用和返回,跳轉(zhuǎn)指令BL采用了相對(duì)尋址方式:

BL NEXT ;跳轉(zhuǎn)到子程序NEXT處執(zhí)行
……
NEXT
……
MOV PC,LR ;從子程序返回
8. 堆棧尋址、批量加載/存儲(chǔ)指令

堆棧是一種數(shù)據(jù)結(jié)構(gòu),按先進(jìn)后出(First In Last Out,F(xiàn)ILO)的方式工作,使用一個(gè)稱作堆棧指針的專用寄存器指示當(dāng)前的操作位置,堆棧指針總是指向棧頂。

批量數(shù)據(jù)加載/存儲(chǔ)指令可以一次在一片連續(xù)的存儲(chǔ)器單元和多個(gè)寄存器之間傳送數(shù)據(jù)。常用的加載存儲(chǔ)指令如下:

LDM批量數(shù)據(jù)加載指令
STM批量數(shù)據(jù)存儲(chǔ)指令

LDM(或STM)指令的格式為:

LDM(或STM){條件}{類型} 基址寄存器{!},寄存器列表{∧}

LDM(或STM)指令用于從由基址寄存器所指示的一片連續(xù)存儲(chǔ)器到寄存器列表所指示的多個(gè)寄存器之間傳送數(shù)據(jù),該指令的常見用途是將多個(gè)寄存器的內(nèi)容入?;虺鰲?。其中,{類型}為以下幾種情況:

IA 每次傳送后地址加1;
IB 每次傳送前地址加1;
DA 每次傳送后地址減1;
DB 每次傳送前地址減1;
FD 滿遞減堆棧; 向低地址方向生長(zhǎng)
ED 空遞減堆棧;
FA 滿遞增堆棧; 向高地址方向生長(zhǎng)
EA 空遞增堆棧;
【滿堆棧】:堆棧指針SP指向最后壓入堆棧的有效數(shù)據(jù)項(xiàng)
【空堆棧】:堆棧指針指向下一個(gè)要放入數(shù)據(jù)的空位置

「【特別注意】」

{?。秊榭蛇x后綴,若選用該后綴,則當(dāng)數(shù)據(jù)傳送完畢之后,將最后的地址寫入基址寄存器,否則基址寄存器的內(nèi)容不改變。
基址寄存器不允許為R15,寄存器列表可以為R0~R15的任意組合。
{∧}為可選后綴,當(dāng)指令為L(zhǎng)DM且寄存器列表中包含R15,選用該后綴時(shí)表示:除了正常的數(shù)據(jù)傳送之外,還將SPSR復(fù)制到CPSR。同時(shí),該后綴還表示傳入或傳出的是用戶模式下的寄存器,而不是當(dāng)前模式下的寄存器。

如:

STMFD R13!,{R0,R4-R12,LR} ;將寄存器列表中的寄存器(R0,R4到R12,LR)存入堆棧,向低地址方向生長(zhǎng)。
LDMFD R13!,{R0,R4-R12,PC} ;將堆棧內(nèi)容恢復(fù)到寄存器(R0,R4到R12,LR)。

【注意】要壓棧的寄存器順序可以亂序,但是實(shí)際壓棧和出棧仍然會(huì)將寄存器順序調(diào)整后再操作。

9. 舉例例1 數(shù)組求和

編寫一個(gè)ARM匯編程序,累加一個(gè)“數(shù)組”的所有元素,碰上0時(shí)停止。結(jié)果放入 r4。

「實(shí)在步驟如下:」1) 在源文件末尾按如下方式聲明“數(shù)組”:

array:
.word 0x11
.word 0x22
.word 0

2) 用r0指向“數(shù)組”的入口

LDR r0,=array

3) 使用LDR r1,[r0],#4從“數(shù)組”中裝載數(shù)據(jù)4) 累加并放入r45) 循環(huán),直到r1為06) 停止,進(jìn)入死循環(huán)

代碼:

area first, code, readonly
code32
entry
start
ldr r0,=array
; adr r0,array ;ADR為小范圍的地址讀取偽指令
loop
ldr r1,[r0],#4
cmp r1,#0
addne r4,r4,r1
bne loop
stop
b stop
DCD 偽操作 數(shù)據(jù)緩沖池技術(shù)
; dcd 機(jī)器碼
array
dcd 0x11
dcd 0x22
dcd 0

我們看一下最終執(zhí)行代碼在內(nèi)存中的機(jī)器碼對(duì)比圖

由上圖可知:

ldr r0,=array,編譯器會(huì)計(jì)算出array標(biāo)號(hào)的地址0x0018,注意該值是偏移當(dāng)前指令所在內(nèi)存位置的偏移量,所以該指令最終被翻譯成ldr r0,[pc,#0x001c]

為什么是0x001c而不是0x0018呢?剛上電時(shí)此時(shí)pc的值是-4,因?yàn)橄乱粭l要執(zhí)行的指令的0x0000這個(gè)地址的指令

數(shù)組元素的3個(gè)值依次存放在0x0018、0x001c、0x001c這3個(gè)地址中l(wèi)dr r1,[r0],#4每次取出r0指向的內(nèi)存的值并寫入到r1,同時(shí)將r0值自加4bne loop 的loop被編譯器計(jì)算為地址0x0004例2 內(nèi)存數(shù)據(jù)讀寫

將某個(gè)整型值寫入到內(nèi)存0x40000000 中然后再將其讀出。

代碼:

area first, code, readonly
code32
entry
start
mov r0, #0x10000003
mov r1, #0x40000000 ; SAMSUNG 2410 , 2410 = > sram 0x40000000 0x3fffff00
str r0, [r1] ;內(nèi)存單元的地址r1寄存器的內(nèi)容指示
ldr r2,[r1]
stop
b stop
end

做這個(gè)實(shí)驗(yàn)之前需要做以下設(shè)置。IRAM地址為0x40000000,size設(shè)置0x1000,就是我們測(cè)試用的IRAM地址范圍是0x40000000-0x40001000

注意,該內(nèi)存地址不是隨意設(shè)置的,查看S3C2440A用戶手冊(cè)【因?yàn)槲覀?a href="http://m.xsypw.cn/analog/" target="_blank">模擬的是S3C2440A這個(gè)soc】,從下圖可以清楚看到ram地址空間。

「數(shù)據(jù)寫入內(nèi)存:」

「從內(nèi)存讀取數(shù)據(jù):」

例3 數(shù)據(jù)壓棧退棧

先將棧地址設(shè)置為將要壓棧的數(shù)據(jù)存入寄存器r1-r5中,然后

area first, code, readonly
code32
entry
Start
;mov r0, #0x40000000
ldr sp, =0x40001000 ;注意地址
mov r1, #0x11
mov r2, #0x22
mov r3, #0x33
mov r5, #0x55
; 壓棧
stmfd sp!, {r1-r3, r5}
;stmia r0!, {r1-r3, r5} ; 加感嘆號(hào)是自動(dòng)修改基地址
mov r1, #0
mov r2, #0
mov r3, #0
mov r5, #0
ldmfd sp!, {r1-r3, r5}
;ldmdb r0!, {r2,r1,r3, r5} ; 寄存列表書寫順序無所謂, 低地址內(nèi)容對(duì)應(yīng)低編號(hào)寄存器
stop
b stop
end

在壓棧前,內(nèi)存0x40001000地址全為0。sp的值為0x40001000。

執(zhí)行命令ldmfd sp!, {r1-r3, r5}壓棧后,因?yàn)槲覀兪菨M遞減堆棧,并且SP后又!,所以內(nèi)存0x40000ff0地址開始的數(shù)據(jù)是0x11、0x22、0x33、0x44,sp的值修改為為0x40000ff0。以下是壓棧后內(nèi)存的數(shù)據(jù):

例4 函數(shù)嵌套調(diào)用

當(dāng)有多級(jí)函數(shù)嵌套,函數(shù)返回值我們不可能都存儲(chǔ)在通用寄存器中,必須利用ldm將程序跳轉(zhuǎn)前的寄存器值以及函數(shù)的返回地址壓棧。

area first, code, readonly
code32
entry
start
ldr sp, =0x40002000
mov r1, #0x11
mov r2, #0x22
mov r3, #0x33
mov r5, #0x55
bl child_func1 ; 【先寫跳轉(zhuǎn)到 child_func1,再寫跳轉(zhuǎn)到child_func】
add r0, r1,r2
stop
b stop
; 非葉子函數(shù)
child_func
stmfd sp!, {r1-r3,r5,lr} ;;;在子函數(shù)里首先將所有寄存器值壓棧保存,
;;防止在子函數(shù)里篡改原本在主函數(shù)里運(yùn)算需要的值,
;;通常需要把r0-r12全都保存,為了安全和程序通用性應(yīng)該這么做
mov r1, #10 ;;在這里子函數(shù)想怎么做自己的事情就可以做自己的事情
bl child_func1
ldmfd sp!, {r1-r3,r5,lr};;;;; 放在主函數(shù)bl之后的第一句行嗎?
mov pc, lr
child_func1
stmfd sp!, {r1-r3,r5};;;不論嵌套多少層子函數(shù),都是先壓棧,
mov r1, #11
ldmfd sp!, {r1-r3,r5};;對(duì)應(yīng)的,在返回到自己的父函數(shù)之前將自己出棧
mov pc, lr
end

讀者可以自己debug,查看內(nèi)存的內(nèi)容變化

四、ldrex 和 strex1. LDREX

LDREX可從內(nèi)存加載數(shù)據(jù)。

如果物理地址有共享TLB屬性,則「LDREX會(huì)將該物理地址標(biāo)記為由當(dāng)前處理器獨(dú)占訪問」,并且會(huì)「清除該處理器對(duì)其他任何物理地址的任何獨(dú)占訪問標(biāo)記」。

否則,會(huì)標(biāo)記:執(zhí)行處理器已經(jīng)標(biāo)記了一個(gè)物理地址,但訪問尚未完畢。

2. STREX

STREX可在一定條件下向內(nèi)存存儲(chǔ)數(shù)據(jù)。

條件具體如下:

如果物理地址沒有共享TLB屬性,且執(zhí)行處理器有一個(gè)已標(biāo)記但尚未訪問完畢的物理地址,那么將會(huì)進(jìn)行存儲(chǔ),清除該標(biāo)記,并在Rd中返回值0。

如果物理地址沒有共享TLB屬性,且執(zhí)行處理器也沒有已標(biāo)記但尚未訪問完畢的物理地址,那么將不會(huì)進(jìn)行存儲(chǔ),而會(huì)在Rd中返回值1。

如果物理地址有共享TLB屬性,且已被標(biāo)記為由執(zhí)行處理器獨(dú)占訪問,那么將進(jìn)行存儲(chǔ),清除該標(biāo)記,并在Rd中返回值0。

如果物理地址有共享TLB屬性,但沒有標(biāo)記為由執(zhí)行處理器獨(dú)占訪問,那么不會(huì)進(jìn)行存儲(chǔ),且會(huì)在Rd中返回值1。

3. 語法LDREX{cond} Rt, [Rn {, #offset}]
STREX{cond} Rd, Rt, [Rn {, #offset}]
LDREXB{cond} Rt, [Rn] 字節(jié)加載
STREXB{cond} Rd, Rt, [Rn] 字節(jié)存儲(chǔ)
LDREXH{cond} Rt, [Rn] 半字加載
STREXH{cond} Rd, Rt, [Rn] 半字存儲(chǔ)
LDREXD{cond} Rt, Rt2, [Rn] 雙字加載
STREXD{cond} Rd, Rt, Rt2, [Rn] 雙字存儲(chǔ)

其中:

cond
是一個(gè)可選的條件代碼(請(qǐng)參閱條件執(zhí)行)。
Rd
是存放返回狀態(tài)的目標(biāo)寄存器。
Rt
是要加載或存儲(chǔ)的寄存器。
Rt2
為進(jìn)行雙字加載或存儲(chǔ)時(shí)要用到的第二個(gè)寄存器。
Rn
是內(nèi)存地址所基于的寄存器。
offset
為應(yīng)用于 Rn 中的值的可選偏移量。offset 只可用于 Thumb-2 指令中。如果省略 offset,則認(rèn)為偏移量為 0。
實(shí)現(xiàn)原子操作

利用 LDREX 和 STREX 可在多個(gè)處理器和共享內(nèi)存系統(tǒng)之前實(shí)現(xiàn)進(jìn)程間通信

原理

將對(duì)一個(gè)內(nèi)存地址的原子操作拆分成兩個(gè)步驟,一起完成對(duì)內(nèi)存的原子操作??梢岳斫鉃閳?zhí)行LDREX Rd [Rs]指令會(huì)標(biāo)記對(duì)[Rs]這個(gè)內(nèi)存地址的訪問是獨(dú)占狀態(tài)(exclusive state)。而執(zhí)行STREX R0 Rd [Rs]指令會(huì)讓先前處于獨(dú)占狀態(tài)的內(nèi)存地址[Rs]轉(zhuǎn)變?yōu)檎顟B(tài),并且設(shè)置R0為0。若執(zhí)行STREX R0 Rd [Rs]指令時(shí),內(nèi)存地址[Rs]是正常狀態(tài),則指令的存儲(chǔ)動(dòng)作會(huì)失敗,并且R0置為1。

linux 中原子操作對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)為 atomic_t,定義如下:

typedef struct {
int counter;
} atomic_t;

本質(zhì)上就是一個(gè)整型變量。

比如我們要對(duì)原子變量實(shí)行加操作,使用獨(dú)占指令完成累加操作。

#if __LINUX_ARM_ARCH__ >= 6 ----(1)
static inline void atomic_add(int i, atomic_t *v)

unsigned long tmp;
int result;
// 使用獨(dú)占指令讀取,然后執(zhí)行加操作,獨(dú)占寫失敗時(shí)就重新執(zhí)行
prefetchw(&v->counter); ----(2)
__asm__ __volatile__(
"@ atomic_add" ----(3)
"1: ldrex %0, [%3]" ----(4)
" add %0, %0, %4" ----(5)
" strex %1, %0, [%3]" ----(6)
" teq %1, #0" ----(7)
" bne 1b"
: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter) ---對(duì)應(yīng)%0,%1,%2
: "r" (&v->counter), "Ir" (i) ----對(duì)應(yīng)%3,%4
: "cc");

#else
#ifdef CONFIG_SMP

原理:

(1)ARMv6之前的CPU并不支持SMP,之后的ARM架構(gòu)都是支持SMP的(例如我們熟悉的ARMv7-A)。因此,對(duì)于ARM處理,其原子操作分成了兩個(gè)陣營(yíng),一個(gè)是支持SMP的ARMv6之后的CPU,另外一個(gè)就是ARMv6之前的,只有單核架構(gòu)的CPU。對(duì)于UP,原子操作就是通過關(guān)閉CPU中斷來完成的。

(2)這里的代碼和preloading cache相關(guān)。在strex指令之前將要操作的memory內(nèi)容加載到cache中可以顯著提高性能。

(3)其中%3就是input operand list中的”r” (&v->counter),r是限制符(constraint),用來告訴編譯器gcc,你看著辦吧,你幫我選擇一個(gè)通用寄存器保存該操作數(shù)吧。

%0 對(duì)應(yīng)output openrand list中的”=&r” (result),= 表示該操作數(shù)是write only的,& 表示該操作數(shù)是一個(gè)earlyclobber operand,

編譯器在處理嵌入式匯編的時(shí)候,傾向使用盡可能少的寄存器,如果output operand沒有&修飾的話,匯編指令中的input和output操作數(shù)會(huì)使用同樣一個(gè)寄存器。因此,&確保了%3和%0使用不同的寄存器。

(5)完成步驟(4)后,%0這個(gè)output操作數(shù)已經(jīng)被賦值為atomic_t變量的old value,這里的操作是要給old value加上i。

這里%4對(duì)應(yīng)”Ir” (i),這里“I”這個(gè)限制符對(duì)應(yīng)ARM平臺(tái),表示這是一個(gè)有特定限制的立即數(shù),該數(shù)必須是0~255之間的一個(gè)整數(shù)通過rotation的操作得到的一個(gè)32bit的立即數(shù)。

這是和ARM的data-processing instructions如何解析立即數(shù)有關(guān)的。每個(gè)指令32個(gè)bit,其中12個(gè)bit被用來表示立即數(shù),其中8個(gè)bit是真正的數(shù)據(jù),4個(gè)bit用來表示如何rotation。

(6)這一步將修改后的new value保存在atomic_t變量中。是否能夠正確的操作的狀態(tài)標(biāo)記保存在%1操作數(shù)中,也就是”=&r” (tmp)。

(7)檢查memory update的操作是否正確完成,如果OK,皆大歡喜,如果發(fā)生了問題(有其他的內(nèi)核路徑插入),那么需要跳轉(zhuǎn)到lable 1那里,從新進(jìn)行一次read-modify-write的操作。

從0學(xué)arm系列合集

1. 到底什么是Cortex、ARMv8、arm架構(gòu)、ARM指令集、soc?一文幫你梳理基礎(chǔ)概念【科普

2. 嵌入式工程師到底要不要學(xué)習(xí)ARM匯編指令?

3. 1. 從0開始學(xué)ARM-安裝Keil MDK uVision集成開發(fā)環(huán)境

4. 2. 從0開始學(xué)ARM-CPU原理,基于ARM的SOC講解

5. 3. 從0開始學(xué)ARM-ARM模式、寄存器、流水線

6. 4. 從0開始學(xué)ARM-ARM匯編指令其實(shí)很簡(jiǎn)單

審核編輯:符乾江
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • ARM
    ARM
    +關(guān)注

    關(guān)注

    134

    文章

    9180

    瀏覽量

    369470
  • 可編程邏輯
    +關(guān)注

    關(guān)注

    7

    文章

    517

    瀏覽量

    44192
  • MRS
    MRS
    +關(guān)注

    關(guān)注

    0

    文章

    7

    瀏覽量

    7657
  • MSR
    MSR
    +關(guān)注

    關(guān)注

    0

    文章

    18

    瀏覽量

    8033
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    接口的控制與狀態(tài)寄存器什么作用

    接口的控制與狀態(tài)寄存器(Control and Status Registers,簡(jiǎn)稱CSR)是計(jì)算機(jī)系統(tǒng)中用于控制和監(jiān)控硬件設(shè)備操作的寄存器。它們是硬件設(shè)備與其驅(qū)動(dòng)程序之間的橋梁,允
    的頭像 發(fā)表于 10-17 10:42 ?625次閱讀

    什么是寄存器移位尋址

    寄存器移位尋址是一種特定的尋址方式,主要出現(xiàn)在某些處理架構(gòu)中,如ARM指令集。這種尋址方式在處理數(shù)據(jù)移動(dòng)和操作時(shí)提供了極大的靈活性和效率。下面將從定義、工作原理、特點(diǎn)、應(yīng)用場(chǎng)景以及與
    的頭像 發(fā)表于 10-05 17:38 ?493次閱讀

    微處理寄存器的作用

    微處理中的寄存器是計(jì)算機(jī)體系結(jié)構(gòu)中的核心組成部分,它們扮演著至關(guān)重要的角色。寄存器是一種高速的存儲(chǔ)單元,用于暫時(shí)存儲(chǔ)數(shù)據(jù)、指令和地址等信息,以便微處理
    的頭像 發(fā)表于 10-05 15:07 ?720次閱讀

    ARM處理寄存器組織及功能

    ARM處理寄存器組織是其核心架構(gòu)的重要組成部分,對(duì)于理解ARM處理的運(yùn)行機(jī)制和性能特點(diǎn)具有重要意義。以下是對(duì)
    的頭像 發(fā)表于 09-10 11:11 ?1699次閱讀

    ARM寄存器的分類及功能

    ARM寄存器ARM處理內(nèi)部的重要組成部分,它們?cè)谔幚?b class='flag-5'>器的運(yùn)算、控制以及數(shù)據(jù)存儲(chǔ)等方面發(fā)揮著至關(guān)重要的作用。下面,我們將從
    的頭像 發(fā)表于 09-05 14:18 ?1952次閱讀

    通用寄存器是什么意思

    在計(jì)算機(jī)體系結(jié)構(gòu)中,通用寄存器是中央處理(CPU)內(nèi)部最為核心和基礎(chǔ)的組成部分之一。它們被設(shè)計(jì)為能夠存儲(chǔ)和傳輸各種類型的數(shù)據(jù)和指令,是CPU進(jìn)行數(shù)據(jù)處理和運(yùn)算的關(guān)鍵工具。通用寄存器
    的頭像 發(fā)表于 09-05 14:13 ?1254次閱讀

    寄存器的類型和作用

    在計(jì)算機(jī)科學(xué)中,寄存器(Register)是一種高速存儲(chǔ)單元,它位于CPU內(nèi)部,與CPU的運(yùn)算單元和邏輯控制單元緊密相連。寄存器的主要作用是暫時(shí)存儲(chǔ)指令、操作數(shù)和地址等臨時(shí)數(shù)據(jù),以便CPU快速
    的頭像 發(fā)表于 09-05 14:11 ?2692次閱讀

    寄存器是什么意思?寄存器是如何構(gòu)成的?

    在計(jì)算機(jī)科學(xué)中,寄存器(Register)是一個(gè)高速存儲(chǔ)單元,它位于中央處理(CPU)內(nèi)部,用于存儲(chǔ)計(jì)算機(jī)程序執(zhí)行過程中所需要的數(shù)據(jù)、指令地址或
    的頭像 發(fā)表于 08-02 18:23 ?4945次閱讀
    <b class='flag-5'>寄存器</b>是什么意思?<b class='flag-5'>寄存器</b>是如何構(gòu)成的?

    寄存器尋址和直接尋址的區(qū)別

    寄存器尋址和直接尋址是計(jì)算機(jī)指令系統(tǒng)中的兩種基本尋址方式。它們?cè)?b class='flag-5'>指令的執(zhí)行過程中起著至關(guān)重要的作用,決定了指令操作數(shù)的來源和目標(biāo)。下面我們將介紹這兩種尋址方式的特點(diǎn)、區(qū)別以及在實(shí)際應(yīng)用
    的頭像 發(fā)表于 07-12 10:42 ?2462次閱讀

    寄存器尋址的實(shí)現(xiàn)方式

    在計(jì)算機(jī)體系結(jié)構(gòu)中,寄存器尋址是一種常見的尋址方式,它允許程序直接訪問CPU內(nèi)部的寄存器寄存器尋址可以提高
    的頭像 發(fā)表于 07-12 10:36 ?874次閱讀

    寄存器分為基本寄存器和什么兩種

    ,它們用于存儲(chǔ)指令、數(shù)據(jù)和地址等信息。基本寄存器的容量通常較小,但訪問速度非??欤?yàn)樗鼈兣cCPU的執(zhí)行單元緊密相連。 基本寄存器的分類 基本寄存器
    的頭像 發(fā)表于 07-12 10:31 ?1634次閱讀

    PLC移位寄存器指令的工作過程

    在工業(yè)自動(dòng)化領(lǐng)域,可編程序控制器(PLC)的應(yīng)用日益廣泛。作為工業(yè)控制的核心設(shè)備,PLC不僅具備強(qiáng)大的數(shù)據(jù)處理能力,還擁有豐富的指令系統(tǒng),以滿足各種復(fù)雜的控制需求。其中,移位寄存器指令
    的頭像 發(fā)表于 06-15 17:37 ?1939次閱讀

    什么是寄存器?有哪些功能和應(yīng)用?

    在計(jì)算機(jī)科學(xué)中,寄存器(Register)是一個(gè)高速存儲(chǔ)單元,用于存儲(chǔ)計(jì)算機(jī)程序執(zhí)行過程中所需要的數(shù)據(jù)、指令地址或狀態(tài)信息。它們是計(jì)算機(jī)體系結(jié)構(gòu)中至關(guān)重要的組成部分,對(duì)計(jì)算機(jī)的運(yùn)算速度
    的頭像 發(fā)表于 05-30 17:14 ?1.3w次閱讀

    干貨滿滿:ARM的內(nèi)核寄存器講解

    內(nèi)核寄存器與外設(shè)寄存器: 內(nèi)核寄存器與外設(shè)寄存器是完全不同的概念。內(nèi)核寄存器是指 CPU 內(nèi)部的寄存器
    發(fā)表于 04-17 11:47 ?4359次閱讀
    干貨滿滿:<b class='flag-5'>ARM</b>的內(nèi)核<b class='flag-5'>寄存器</b>講解

    loop指令執(zhí)行時(shí),隱含的寄存器

    寄存器的值是否為。如果不為,則跳轉(zhuǎn)到指定的循環(huán)體代碼塊執(zhí)行,并在執(zhí)行完循環(huán)體后再次執(zhí)行l(wèi)oop指令。如果CX寄存器的值為
    的頭像 發(fā)表于 02-14 16:15 ?1053次閱讀
    主站蜘蛛池模板: 国内精品久久久久久久久蜜桃 | 青草久草视频 | 美女黄色毛片免费看 | 美女扒开内裤让男人桶 | 久久天天躁夜夜躁狠狠 | 男女性gif抽搐出入 男女性高爱潮免费的国产 男女性高爱麻豆 | 美国一级做a一级爱视频 | 77se77亚洲欧美在线大屁股 | 青草久草视频 | 国产免费高清福利拍拍拍 | 亚洲午夜视频 | 在线观看免费视频网站色 | 免费黄色一级毛片 | 三级成人网 | 久久天天躁夜夜躁狠狠85麻豆 | 性色欧美| 亚洲午夜一级毛片 | 爱爱免费网站 | 免费看男女下面日出水视频 | 午夜精品福利在线 | 轻点灬大ji巴太粗太大了小说 | 天天爽天天干天天操 | 黄色三级视频在线观看 | 亚洲国产欧美精品一区二区三区 | 成人欧美一区二区三区白人 | 日本不卡一区在线 | 大尺度很肉污的古代小说 | 国产精品片 | 中国又粗又大又爽的毛片 | 久久青草18免费观看网站 | 国产aaaaa一级毛片 | 久色网| 网站在线观看视频 | 色天天综合色天天看 | 国产成人精品系列在线观看 | 特黄十八岁大片 | 国产成人影院 | xxx86日本人| 欧美激情二区三区 | 狠狠色噜狠狠狠狠 | 午夜黄色福利视频 |