<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

零基礎學ARM:程序狀態寄存器訪問指令解析

電子設計 ? 來源:電子設計 ? 作者:電子設計 ? 2020-12-24 13:36 ? 次閱讀

一、程序狀態寄存器訪問指令

ARM微處理器支持程序狀態寄存器訪問指令,用于在程序狀態寄存器和通用寄存器之間傳送數據。

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

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

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

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

位[31:24]為條件標志位域,用f表示;

位[23:16]為狀態位域,用s表示;

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

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

該指令通常用于恢復或改變程序狀態寄存器的內容,在使用時,一般要在MSR指令中指明將要操作的域。如:

MSR CPSR,R0 ;傳送R0的內容到CPSR

MSR SPSR,R0 ;傳送R0的內容到SPSR

MSR CPSR_c,R0 ;傳送R0的內容到SPSR,但僅僅修改CPSR中的控制位域
應用舉例使能中斷

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

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

執行結果:

第8行【其實第8行還沒有執行】:

當前模式時SVC ,因為開機商店屬于reset異常,而該異常會自動進入svc模式CPSR的值是0X000000D39行

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

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

msr cpsr_c,r0 將構造好的值寫回CPSR,此時CPSR的I 位已經為0從而實現了中斷使能禁止中斷同理,我們要關閉中斷,只需要將CPSR的I位設置為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
設置各模式的棧地址要想初始化各個模式的棧地址,必須首先切換到對應的模式,然后再將棧地址設置到寄存器sp即可。

代碼:

area reset,code
code32
entry
start
bl stack_init
stack_init ; 棧指針初始化函數
; @undefine_stack
msr cpsr_c,#0xdb ; 切換到未定義異常
ldr sp,=0x34000000 ; 棧指針為內存最高地址,棧為倒生的棧
; ??臻g的最后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 ; ??臻g為1M,0x33e00000~0x33d00000
; @ sys_stack
msr cpsr_c,#0xdf ; 切換到系統模式
ldr sp,=0x33d00000 ; ??臻g為1M,0x33d00000~0x33c00000
msr cpsr_c,#0xd3 ; 切換回管理模式
mov pc,lr
end

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

8行

模式切換前,當前模式時svc模式,CPSR的值是0x000000D3注意看下SVC和undef模式的SP值都是09行

msr cpsr_c ,# 0xdb 直接對CPSR進行賦值,將當前模式設置為undef模式Current模式看到的LR寄存器值變成了0,因為模式切換成了undef模式,該模式下有自己的LR、SP寄存器SVC模式的私有寄存器SP和LR沒有改變12行

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

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

二、尋址方式

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

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

1. 加載存儲指令

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

我們之前講的尋址方式都是直接對立即數或者寄存器尋址,如果我們想訪問外部存儲器的某個內存地址或者一些外設的控制器寄存器該如何操作呢?

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

訪問外存LDR指令

LDR指令的格式為:

LDR{條件} 目的寄存器,<存儲器地址>
LDR指令用于從存儲器中將一個32位的字數據傳送到目的寄存器中。

1) 用于從存儲器中讀取32位的字數據到通用寄存器,然后對數據進行處理。2) 當程序計數器PC作為目的寄存器時,指令從存儲器中讀取的字數據被當作目的地址,從而可以實現程序流程的跳轉。如:

LDR R0,[R1] ;將存儲器地址為R1的字數據讀入寄存器R0。
LDR R0,[R1,R2] ;將存儲器地址為R1+R2的字數據讀入寄存器R0。
LDR R0,[R1,#8] ;將存儲器地址為R1+8的字數據讀入寄存器R0。
LDR R0,[R1,R2] ! ;將存儲器地址為R1+R2的字數據讀入寄存器R0,并將
;新地址R1+R2寫入R1。
LDR R0,[R1,#8] ! ;將存儲器地址為R1+8的字數據讀入寄存器R0,并將新
;地址R1+8寫入R1。
LDR R0,[R1],R2 ;將存儲器地址為R1的字數據讀入寄存器R0,并將新地
;址R1+R2寫入R1。
LDR R0,[R1,R2,LSL#2]! ;將存儲器地址為R1+R2×4的字數據讀入寄存器R0,
;并將新地址R1+R2×4寫入R1。
LDR R0,[R1],R2,LSL#2 ;將存儲器地址為R1的字數據讀入寄存器R0,并將新地
;址R1+R2×4寫入R1。
STR指令

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

STR R0,[R1],#8 ;將R0中的字數據寫入以R1為地址的存儲器中,并將新地址R1+8寫入R1。
STR R0,[R1,#8] ;將R0中的字數據寫入以R1+8為地址的存儲器中。

LDR/STR指令都可以加B、H、SB、SH的后綴,分別表示加載/存儲字節、半字、帶符號的字節、帶符號的半字。如LDRB指令表示從存儲器加載一個字節進寄存器。當使用這些后綴時,要注意所使用的存儲器要支持訪問的數據寬度。

LDRB指令

LDRB指令的格式為:

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

LDRB指令用于從存儲器中將一個8位的字節數據傳送到目的寄存器中,同時將寄存器的高24位清零。該指令通常用于從存儲器中讀取8位的字節數據到通用寄存器,然后對數據進行處理。

「指令示例:」

LDRB R0,[R1] ;將存儲器地址為R1的字節數據讀入寄存器R0,并將R0的高24位清零。
LDRB R0,[R1,#8];將存儲器地址為R1+8的字節數據讀入寄存器R0,并將R0的高24位清零。
LDRH指令

LDRH指令的格式為:

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

LDRH指令用于從存儲器中將一個16位的半字數據傳送到目的寄存器中,同時將寄存器的高16位清零。該指令通常用于從存儲器中讀取16位的半字數據到通用寄存器,然后對數據進行處理。

「指令示例:」

LDRH R0,[R1] ;將存儲器地址為R1的半字數據讀入寄存器R0,并將R0的高16位清零。
LDRH R0,[R1,R2];將存儲器地址為R1+R2的半字數據讀入寄存器R0,并將R0的高16位清零。
舉例1) STR r0,[r1,#12]

如上圖所示:

寄存器r0中的值是0x5,r1中的值是0x200將r1的值加上#12,得到地址0x20c將r0寄存器里的值發送給該地址對應的內存,即向地址0x20c中賦值0x52) STR r0,[r1],#12

如上圖所示:

寄存器r0的值是0x5,r1中的值是0x200將r0寄存器里的值發送給該r1中的值對應的內存,即向地址0x200中賦值0x5將r1的值加上#12并賦值給r1,r1的值就變成了0x20c

「擴展:」比如有以下c代碼

int *ptr;
x = *ptr++;

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

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

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

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

在以上兩條指令中,第二個源操作數即為立即數,要求以“?!睘榍熬Y,對于以十六進制表示的立即數,還要求在“?!焙蠹由稀?x”或“&”。

3. 寄存器尋址

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

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

該指令的執行效果是將寄存器R1和R2的內容相加,其結果存放在寄存器R0中。

4. 寄存器間接尋址

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

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

在第一條指令中,以寄存器R2的值作為操作數的地址,在存儲器中取得一個操作數后與R1相加,結果存入寄存器R0中。第二條指令將以R1的值為地址的存儲器中的數據傳送到R0中。

5. 基址變址尋址

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

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. 多寄存器尋址

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

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

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

7. 相對尋址

與基址變址尋址方式相類似,相對尋址以程序計數器PC的當前值為基地址,指令中的地址標號作為偏移量,將兩者相加之后得到操作數的有效地址。以下程序段完成子程序的調用和返回,跳轉指令BL采用了相對尋址方式:

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

堆棧是一種數據結構,按先進后出(First In Last Out,FILO)的方式工作,使用一個稱作堆棧指針的專用寄存器指示當前的操作位置,堆棧指針總是指向棧頂。

批量數據加載/存儲指令可以一次在一片連續的存儲器單元和多個寄存器之間傳送數據。常用的加載存儲指令如下:

LDM批量數據加載指令
STM批量數據存儲指令

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

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

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

IA 每次傳送后地址加1;
IB 每次傳送前地址加1;
DA 每次傳送后地址減1;
DB 每次傳送前地址減1;
FD 滿遞減堆棧; 向低地址方向生長
ED 空遞減堆棧;
FA 滿遞增堆棧; 向高地址方向生長
EA 空遞增堆棧;
【滿堆?!浚憾褩V羔楽P指向最后壓入堆棧的有效數據項
【空堆?!浚憾褩V羔樦赶蛳乱粋€要放入數據的空位置

「【特別注意】」

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

如:

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

【注意】要壓棧的寄存器順序可以亂序,但是實際壓棧和出棧仍然會將寄存器順序調整后再操作。

9. 舉例例1 數組求和

編寫一個ARM匯編程序,累加一個“數組”的所有元素,碰上0時停止。結果放入 r4。

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

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

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

LDR r0,=array

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

代碼:

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 偽操作 數據緩沖池技術
; dcd 機器碼
array
dcd 0x11
dcd 0x22
dcd 0

我們看一下最終執行代碼在內存中的機器碼對比圖

由上圖可知:

ldr r0,=array,編譯器會計算出array標號的地址0x0018,注意該值是偏移當前指令所在內存位置的偏移量,所以該指令最終被翻譯成ldr r0,[pc,#0x001c]

為什么是0x001c而不是0x0018呢?剛上電時此時pc的值是-4,因為下一條要執行的指令的0x0000這個地址的指令

數組元素的3個值依次存放在0x0018、0x001c、0x001c這3個地址中ldr r1,[r0],#4每次取出r0指向的內存的值并寫入到r1,同時將r0值自加4bne loop 的loop被編譯器計算為地址0x0004例2 內存數據讀寫

將某個整型值寫入到內存0x40000000 中然后再將其讀出。

代碼:

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

做這個實驗之前需要做以下設置。IRAM地址為0x40000000,size設置0x1000,就是我們測試用的IRAM地址范圍是0x40000000-0x40001000

注意,該內存地址不是隨意設置的,查看S3C2440A用戶手冊【因為我們模擬的是S3C2440A這個soc】,從下圖可以清楚看到ram地址空間。

「數據寫入內存:」

「從內存讀取數據:」

例3 數據壓棧退棧

先將棧地址設置為將要壓棧的數據存入寄存器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} ; 加感嘆號是自動修改基地址
mov r1, #0
mov r2, #0
mov r3, #0
mov r5, #0
ldmfd sp!, {r1-r3, r5}
;ldmdb r0!, {r2,r1,r3, r5} ; 寄存列表書寫順序無所謂, 低地址內容對應低編號寄存器
stop
b stop
end

在壓棧前,內存0x40001000地址全為0。sp的值為0x40001000。

執行命令ldmfd sp!, {r1-r3, r5}壓棧后,因為我們是滿遞減堆棧,并且SP后又!,所以內存0x40000ff0地址開始的數據是0x11、0x22、0x33、0x44,sp的值修改為為0x40000ff0。以下是壓棧后內存的數據:

例4 函數嵌套調用

當有多級函數嵌套,函數返回值我們不可能都存儲在通用寄存器中,必須利用ldm將程序跳轉前的寄存器值以及函數的返回地址壓棧。

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 ; 【先寫跳轉到 child_func1,再寫跳轉到child_func】
add r0, r1,r2
stop
b stop
; 非葉子函數
child_func
stmfd sp!, {r1-r3,r5,lr} ;;;在子函數里首先將所有寄存器值壓棧保存,
;;防止在子函數里篡改原本在主函數里運算需要的值,
;;通常需要把r0-r12全都保存,為了安全和程序通用性應該這么做
mov r1, #10 ;;在這里子函數想怎么做自己的事情就可以做自己的事情
bl child_func1
ldmfd sp!, {r1-r3,r5,lr};;;;; 放在主函數bl之后的第一句行嗎?
mov pc, lr
child_func1
stmfd sp!, {r1-r3,r5};;;不論嵌套多少層子函數,都是先壓棧,
mov r1, #11
ldmfd sp!, {r1-r3,r5};;對應的,在返回到自己的父函數之前將自己出棧
mov pc, lr
end

讀者可以自己debug,查看內存的內容變化

四、ldrex 和 strex1. LDREX

LDREX可從內存加載數據。

如果物理地址有共享TLB屬性,則「LDREX會將該物理地址標記為由當前處理器獨占訪問」,并且會「清除該處理器對其他任何物理地址的任何獨占訪問標記」。

否則,會標記:執行處理器已經標記了一個物理地址,但訪問尚未完畢。

2. STREX

STREX可在一定條件下向內存存儲數據。

條件具體如下:

如果物理地址沒有共享TLB屬性,且執行處理器有一個已標記但尚未訪問完畢的物理地址,那么將會進行存儲,清除該標記,并在Rd中返回值0。

如果物理地址沒有共享TLB屬性,且執行處理器也沒有已標記但尚未訪問完畢的物理地址,那么將不會進行存儲,而會在Rd中返回值1。

如果物理地址有共享TLB屬性,且已被標記為由執行處理器獨占訪問,那么將進行存儲,清除該標記,并在Rd中返回值0。

如果物理地址有共享TLB屬性,但沒有標記為由執行處理器獨占訪問,那么不會進行存儲,且會在Rd中返回值1。

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

其中:

cond
是一個可選的條件代碼(請參閱條件執行)。
Rd
是存放返回狀態的目標寄存器。
Rt
是要加載或存儲的寄存器。
Rt2
為進行雙字加載或存儲時要用到的第二個寄存器。
Rn
是內存地址所基于的寄存器。
offset
為應用于 Rn 中的值的可選偏移量。offset 只可用于 Thumb-2 指令中。如果省略 offset,則認為偏移量為 0。
實現原子操作

利用 LDREX 和 STREX 可在多個處理器和共享內存系統之前實現進程間通信。

原理

將對一個內存地址的原子操作拆分成兩個步驟,一起完成對內存的原子操作??梢岳斫鉃閳绦蠰DREX Rd [Rs]指令會標記對[Rs]這個內存地址的訪問是獨占狀態(exclusive state)。而執行STREX R0 Rd [Rs]指令會讓先前處于獨占狀態的內存地址[Rs]轉變為正常狀態,并且設置R0為0。若執行STREX R0 Rd [Rs]指令時,內存地址[Rs]是正常狀態,則指令的存儲動作會失敗,并且R0置為1。

linux 中原子操作對應的數據結構為 atomic_t,定義如下:

typedef struct {
int counter;
} atomic_t;

本質上就是一個整型變量。

比如我們要對原子變量實行加操作,使用獨占指令完成累加操作。

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

unsigned long tmp;
int result;
// 使用獨占指令讀取,然后執行加操作,獨占寫失敗時就重新執行
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) ---對應%0,%1,%2
: "r" (&v->counter), "Ir" (i) ----對應%3,%4
: "cc");

#else
#ifdef CONFIG_SMP

原理:

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

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

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

%0 對應output openrand list中的”=&r” (result),= 表示該操作數是write only的,& 表示該操作數是一個earlyclobber operand,

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

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

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

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

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

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

從0學arm系列合集

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

2. 嵌入式工程師到底要不要學習ARM匯編指令?

3. 1. 從0開始學ARM-安裝Keil MDK uVision集成開發環境

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

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

6. 4. 從0開始學ARM-ARM匯編指令其實很簡單

審核編輯:符乾江
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • ARM
    ARM
    +關注

    關注

    134

    文章

    8693

    瀏覽量

    362455
  • 可編程邏輯
    +關注

    關注

    7

    文章

    513

    瀏覽量

    43918
  • MRS
    MRS
    +關注

    關注

    0

    文章

    7

    瀏覽量

    7588
  • MSR
    MSR
    +關注

    關注

    0

    文章

    17

    瀏覽量

    7973
收藏 人收藏

    評論

    相關推薦

    干貨滿滿:ARM的內核寄存器講解

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

    loop指令執行時,隱含的寄存器

    當執行loop指令時,隱含的寄存器是CX寄存器。CX寄存器是循環計數器寄存器,它存儲了循環的迭代次數。 在匯編語言中,loop
    的頭像 發表于 02-14 16:15 ?485次閱讀

    arm三個寄存器在gdb調試時的作用

    arm三個寄存器在gdb調試時作用? ARM是一種廣泛使用的微處理器架構,它廣泛應用于移動設備、嵌入式系統和其他高性能計算設備。當我們在使用gdb(GNU調試器)調試ARM
    的頭像 發表于 01-31 10:44 ?299次閱讀

    ARM處理7種工作模式

    CPSR; 早期的ARM核有狀態ARM或Thumb)切換(通過BX等指令修改CPSR寄存器(當前程序
    發表于 12-15 10:15

    CPSR寄存器和APSR寄存器的組成

    程序狀態寄存器的作用就是反映處理器的狀態信息。在程序運行期間我們可以通過查看程序
    的頭像 發表于 10-20 11:38 ?2004次閱讀
    CPSR<b class='flag-5'>寄存器</b>和APSR<b class='flag-5'>寄存器</b>的組成

    如何在特權模式下用arm匯編指令使能和禁止irq中斷?

    如何在特權模式下用arm匯編指令使能和禁止irq中斷? 在 ARM 系統中,中斷是非常常見的一種事件。在特權模式下,可以使用 ARM 匯編指令
    的頭像 發表于 10-19 16:42 ?870次閱讀

    RISC-V CSR寄存器介紹

    RISC-V CSR寄存器 CSR是控制狀態寄存器,RISC-V中CSR寄存器,需要使用csrr、csrw、csrrw等特定指令進行
    的頭像 發表于 10-08 14:53 ?3009次閱讀
    RISC-V CSR<b class='flag-5'>寄存器</b>介紹

    Linux程序狀態寄存器訪問指令

    轉移指令 【跳轉指令】 B 跳轉指令BL 帶返回的跳轉指令BLX 帶返回和狀態切換的跳轉指令BX
    的頭像 發表于 10-07 14:22 ?612次閱讀

    怎樣通過改變寄存器中的內容實現對CPU的控制呢?

    寄存器是CPU中程序員可以用指令讀寫的部件,通過改變寄存器中的內容實現對CPU的控制。
    的頭像 發表于 09-20 15:49 ?835次閱讀
    怎樣通過改變<b class='flag-5'>寄存器</b>中的內容實現對CPU的控制呢?

    寄存器psw中的rs1和rs0的作用是什么?

    寄存器psw中的rs1和rs0的作用是什么?? 寄存器PSW(程序狀態字)是CPU(中央處理器)中的一個重要寄存器,它用于存儲和表示當前
    的頭像 發表于 09-13 11:17 ?5884次閱讀

    《從開始ARM》真心適合新手小白

    逐步建立對ARM架構的理解。書中從基本的ARM架構概述開始,然后深入探討了指令集、寄存器、內存管理單元等重要概念。這種有序的學習路徑確保了初學者能夠循序漸進地掌握復雜的內容,而不至于感
    發表于 09-02 15:29

    Arm64程序調用通用寄存器的使用方法

    下面是Arm64程序調用標準規定的通用寄存器的使用方法。 參數寄存器(X0-X7) 函數參數數量小于等于8個時,使用X0-X7傳遞,大于8個時,多余的使用棧傳遞,函數返回時返回值保存在
    的頭像 發表于 07-28 11:28 ?1910次閱讀
    <b class='flag-5'>Arm</b>64<b class='flag-5'>程序</b>調用通用<b class='flag-5'>寄存器</b>的使用方法

    RAL寄存器模型操作指南

    寄存器模型操作,指的是通過寄存器模型對RTL中寄存器進行讀寫訪問,或者同步寄存器模型與RTL中寄存器
    的頭像 發表于 07-12 09:37 ?741次閱讀
    RAL<b class='flag-5'>寄存器</b>模型操作指南

    詳解PIC系列單片機數據存儲器轉換寄存器指令

    A/D轉換寄存器 這里摘錄一段筆者從網上下載的用PIC16F877單片機芯片(帶Flash存儲器的)完成有關A/D轉換的源程序部分指令,并用它說明有關A/D轉換寄存器
    的頭像 發表于 06-25 13:42 ?715次閱讀

    PRIMASK寄存器開、關總中斷的指令代碼

    我們在使用ARM Cortex-M內核芯片進行產品開發時,有時可能需要暫時開辟一個相對清靜、不被打擾的程序執行環境,以確保某些操作可靠順利完成。這時我們往往會使用所謂開、關總中斷的指令代碼來完成
    的頭像 發表于 06-21 16:32 ?3966次閱讀
    PRIMASK<b class='flag-5'>寄存器</b>開、關總中斷的<b class='flag-5'>指令</b>代碼
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>