處理內(nèi)部數(shù)據(jù)傳輸指令
處理器內(nèi)進(jìn)行數(shù)據(jù)傳遞,常見的操作有如下3種。
- 將數(shù)據(jù)從一個(gè)寄存器傳遞到另外一個(gè)寄存器。
- 將數(shù)據(jù)從一個(gè)寄存器傳遞到特殊寄存器,如CPSR和SPSR寄存器。
- 將立即數(shù)傳遞到寄存器。
數(shù)據(jù)傳輸常用的指令有3個(gè):MOV、MRS、MSR,這3個(gè)指令的用法如下
指令 | 目的 | 源 | 描述 |
---|---|---|---|
MOV | R0 | R1 | 將R1中的數(shù)據(jù)復(fù)制到R0中 |
MRS | R0 | CPSR | 將特殊寄存器中的數(shù)據(jù)復(fù)制R0中 |
MSR | CPSR | R1 | 將R1中的數(shù)據(jù)復(fù)制到特殊寄存器CPSR中 |
詳細(xì)地介紹如何使用這3個(gè)指令。 |
1. MOV指令
MOV指令用于獎(jiǎng)數(shù)據(jù)從一個(gè)寄存器復(fù)制到另外一個(gè)寄存器,或才將一個(gè)立即數(shù)傳遞到寄存器中,使用如下代碼:
MOV R0,R1 @將寄存器R1的數(shù)據(jù)復(fù)制到R0,即R0=R1
MOV R0, #0x12 @將立即數(shù)0x12傳遞給R0寄存器,即R0=0x12
2. MRS指令
MRS 指令用于獎(jiǎng)特殊寄存器(CPSR和SPSR)中的數(shù)據(jù)傳遞給通用寄存器,要讀取特殊寄存器的數(shù)據(jù)只能全用MRS,使用如下代碼:
MRS CPSR,R0 @將CPSP寄存器中和數(shù)據(jù)傳遞給R0 即:R0=CPSR
3. MSR指令
MSR指令和MRS指令剛好相反,MSR指令用來(lái)獎(jiǎng)普通寄存器的數(shù)據(jù)傳遞給特殊寄存器,也就寫特殊寄存器,寫特殊寄存器只能用MSR,使用如下代碼。
MSR CPSR,R0 @將R0的數(shù)據(jù)復(fù)制到CPSR中,即CPSR=R0
【理解】: R 即讀,S即寫”
存儲(chǔ)器訪問指令
ARM不能直接訪問存儲(chǔ)器,比如RAM中的數(shù)據(jù)。1.MX6ULL中的寄存器就是RAM類型的,我們用匯編來(lái)配置I.MX6Ull寄存器時(shí)需要借助存儲(chǔ)器訪問指令,一般先將要配置的值寫入反Rx(x=0~12)寄存器中,然后借助存儲(chǔ)器訪問指令將Rx中的數(shù)據(jù)寫入到I.MX6UL
寄存器中,讀取I.MX6ULL寄存器也是一樣的,只是過程剛好相反。常用的存儲(chǔ)器訪問指令有兩種LDR和STR。用法如下表:
指 令 | 描 述 |
---|---|
LDR Rd,[Rn,# offset | 從存儲(chǔ)器Rn+offset的位置讀取數(shù)據(jù)存放到Rd中 |
STR Rd,[Rn,# offset | 將Rd中的數(shù)據(jù)寫入到存儲(chǔ)器中的Rn+offset位置 |
1. LDR 指令
LDR(載入指令)主要用于從存儲(chǔ)器加載數(shù)據(jù)到Rx中,LDR也可以將一個(gè)立即數(shù)加載到寄存器Rx中,LDR加載立即數(shù)時(shí)要使用“=”,而不是“#”。在嵌入式開發(fā)中,LDR最常用的就是讀取CPU的寄存器值,比如I.MX6ULL有個(gè)寄存器GPIO_GDIR,其地址為0X0209C004,我們現(xiàn)在讀取這個(gè)寄存器中的數(shù)據(jù),如下所示:
LDR R0, = 0X0209C004 @將害存器址0X0209C004加載到R0中,R0=0X0209C004
LDR R1,[R0] @讀取地址0X0209C004中的數(shù)據(jù)到R1寄存器中
上面的代碼就是讀取GPIO1_GDIR中的值,讀取到的寄存器值保存在R1寄存器中,上面代碼中offset是0,沒有用到offset。
2. STR指令
LDR是從存儲(chǔ)器中讀取,STR就是將數(shù)據(jù)寫入到存儲(chǔ)器,同樣以I.MX6ULL寄存器GPIO1_GDIR為例,現(xiàn)在我們要配置寄存器GPIO1_GDIR的值為0X20000002:
LDR R0, = 0X0209C004 @將害存器址0X0209C004加載到R0中,
LDR R1,= 0X20000002 @R1保存要寫入寄存器的值
STR R1,[R0] @將R1的值寫入到R0 中所保存地址中。
【注】LDR指令和STR指令都是按字進(jìn)行讀取和寫入的,也就是操作的32位數(shù)據(jù)。如果要按照字節(jié)、半字節(jié)進(jìn)行操作的話可以在LDR指令后面加上B或者H,比如按字節(jié)操作指令就是LDRB和STRB,按半字節(jié)操作的指令就是LDRH和STRH。
壓棧與出棧指令
我們通常會(huì)在A函數(shù)中調(diào)用B函數(shù),當(dāng)B函數(shù)執(zhí)行完以后再回到A函數(shù)繼續(xù)執(zhí)行。要想在跳回A函數(shù)以后代碼能夠接著正常運(yùn)行,那就必須在跳到B函數(shù)之前將當(dāng)前的處理器狀態(tài)保存起來(lái)(就是保存R0~~~R15這些寄存器值),當(dāng)B函數(shù)執(zhí)行完成以后再用前面的保存的寄存器值恢復(fù)R0~R15即可。保存R0~R15寄存器的操作就叫做現(xiàn)場(chǎng)保護(hù),恢復(fù)R0~R15寄存器的操作就叫做恢復(fù)現(xiàn)場(chǎng)。在進(jìn)行現(xiàn)場(chǎng)保護(hù)時(shí)需要進(jìn)行壓棧(入棧),恢復(fù)現(xiàn)場(chǎng)就要進(jìn)行出棧操作。壓棧的指令為PUSH,出棧的指令為POP,PUSH和POP是一種多存儲(chǔ)和多加載指令,即可一次操作多個(gè)寄存器數(shù)據(jù),其利用當(dāng)前的棧指針SP來(lái)生成地址,PUSH和POP的用法如下:
指令 | 描述 |
---|---|
PUSH reg list | 將寄存器列表存入棧中 |
POP reg list | 從棧中恢復(fù)寄存器列表 |
假如我們要將R0~R4和R12壓入棧中:
PUSH {R0~R5,R12} @將R0~R5,R12壓棧
PUSH {LR}
出棧:
POP {LR}
PPOP {R0~R5,R12} @將R0~R5,R12壓棧
PUSH和POP的另外一種寫法是STMFD SP!和LDMFD SP! 代碼如下列所示:
STMFD SP!,{R0~R5,R12} @R0~R5,R12入棧
STMFD SP!,{LR} @LR入棧
LDMFD SP!, {LR} @LR入棧
LDMFD SP!, {R0~R5,R12} @R0~R5,R12入棧
STMFD與STR不同是一次可以操作多個(gè)寄存器
同理LDMFD與LDR不同也是一次可以操作多個(gè)寄存器。
跳轉(zhuǎn)指令
有多種跳轉(zhuǎn)操作:
直接使用跳轉(zhuǎn)指令B、BL、BX等。
直接向PC寄存器中寫入數(shù)據(jù)。
上述兩種方法都可以完成跳轉(zhuǎn)操作,但是一般常用的是B、BL或BX,用法如下表:| 指令 | 描述 || ---------- | --------------------------------------------------------------------------------------------------------------- |
| B label | 跳轉(zhuǎn)到label,如果跳轉(zhuǎn)滿園超過正確負(fù)2KB,可以指定的B.W label使用32位版本的跳轉(zhuǎn)指令,這樣可以得到較大范圍的跳轉(zhuǎn) |
| BX Rm | 間接跳轉(zhuǎn),跳轉(zhuǎn)到存放于Rm中的地址處,并且切換指令集 |
| BL label | 跳轉(zhuǎn)到標(biāo)號(hào)址,并將返回地址保存在LR中 |
| BLX Rm | 結(jié)合BX和BL的特點(diǎn),跳轉(zhuǎn)到Rm指定的地址,并將返回地址保存在LR中,切換指令集 |
下面重點(diǎn)學(xué)習(xí)一下B和BL指令,因?yàn)橐趨R編中進(jìn)行函數(shù)調(diào)用使用的就是B和BL指令。
- B指令
這是最簡(jiǎn)單的跳轉(zhuǎn)指令,B指令會(huì)將PC寄存器的值設(shè)置為跳轉(zhuǎn)目標(biāo)地址,一旦執(zhí)行B指令,ARM處理器就會(huì)立即跳轉(zhuǎn)到指定的目標(biāo)地址。如果要調(diào)用的函數(shù)不會(huì)返回到原來(lái)的執(zhí)行處,那就可以用B指令。_start: ldr sp, = 0x8020000 @設(shè)置棧指針 b main @跳轉(zhuǎn)到main函數(shù)
上述代碼就是典型的在匯編中初始化語(yǔ)言支行環(huán)境,然后跳轉(zhuǎn)到C語(yǔ)言文件的main函數(shù)中運(yùn)行,上面的代碼只是初始化了SP指針,有些處理器還需要做其他的初始化,比如初始化DDR等。因?yàn)樘D(zhuǎn)到C語(yǔ)言以后再也不會(huì)回到匯編了,所以在第4行使用了B指令來(lái)完成跳轉(zhuǎn)。
- BL指令BL指令相比B指令,在跳轉(zhuǎn)之前會(huì)在寄存器LR(R14)中保存當(dāng)前PC寄存器值,這就可以要過將LR寄存器的值重新加載到PC中來(lái)繼續(xù)從跳轉(zhuǎn)之前的代碼處,這是子程序調(diào)用的一個(gè)常用手段。比如Cortex-A處理器的irq中斷服務(wù)函數(shù)都是用匯編寫的,主要用匯編來(lái)實(shí)現(xiàn)現(xiàn)場(chǎng)的保護(hù)和恢復(fù)、獲取中斷號(hào)等。但是具體的中斷處理過程過者是C函數(shù),所以就會(huì)存在從匯編中調(diào)用C函數(shù)的問題。當(dāng)C語(yǔ)言環(huán)境的中斷處理函數(shù)執(zhí)行完成后返回到irq匯編中斷服務(wù)函數(shù),繼續(xù)處理其他的工作。這個(gè)時(shí)候就不能直接使用B指令了,因?yàn)锽指令一旦跳轉(zhuǎn)就再也不會(huì)回來(lái)了,這個(gè)時(shí)候要使用BL指令。如下所示:’
push {r0, r1} @保存r0,r1
cps #0x13 @進(jìn)入SVC模式,允許其他中斷再次進(jìn)去
bl system_irqhandler @加載C語(yǔ)言中斷處理函數(shù)到r2寄存器
cps #0x12 @進(jìn)入IRQ模式
pop {r0,r1}
str r0,{r1, #0x10} @中斷執(zhí)行完成,寫EOIR
上述代碼中第4行就是執(zhí)行C語(yǔ)言的中斷處理函數(shù),當(dāng)處理完成以后就需要返回來(lái)繼續(xù)執(zhí)行下面的程序,所以使用BL指令。
學(xué)習(xí)總結(jié)
學(xué)習(xí)了常用的匯編指令中的數(shù)據(jù)傳輸: MOV 、MRS、MSR。存儲(chǔ)器LDR、STR。壓棧和出棧指令:PUSH、POP、STMFD SP!LDMFD SP!。跳轉(zhuǎn)指令 B、BX、BL、BLX。了解這些指令后,在分析啟動(dòng)文件中就可以看得懂匯編指令了。
-
寄存器
+關(guān)注
關(guān)注
31文章
5336瀏覽量
120229 -
C語(yǔ)言
+關(guān)注
關(guān)注
180文章
7604瀏覽量
136683 -
匯編指令
+關(guān)注
關(guān)注
0文章
38瀏覽量
11450 -
MRS
+關(guān)注
關(guān)注
0文章
7瀏覽量
7625 -
Cortex-A7
+關(guān)注
關(guān)注
0文章
34瀏覽量
16493
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論