ARM裸機開發(fā)篇2:ARM微處理器指令系統(tǒng)(二)
狀態(tài)操作指令
ARM指令集提供了兩條指令,可直接控制程序狀態(tài)寄存器(Program State Register,PSR)。MRS指令用于把CPSR或SPSR的值傳送到一個寄存器;MSR與之相反,把一個寄存器的內(nèi)容傳送到CPSR或SPSR。這兩條指令相結(jié)合,可用于對CPSR和SPSR進行讀/寫操作。程序狀態(tài)寄存器指令如表所示。
指 令作 用操 作MRS把程序狀態(tài)寄存器的值送到一個通用寄存器Rd=SPRMSR把通用寄存器的值送到程序狀態(tài)寄存器或把一個立即數(shù)送到程序狀態(tài)字PSR[field]=Rm或PSR[field]=immediate
在指令語法中可看到一個稱為fields的項,它可以是控制(C)、擴展(X)、狀態(tài)(S)及標志(F)的組合。
MRS
MRS指令用于將程序狀態(tài)寄存器的內(nèi)容傳送到通用寄存器中。
在ARM處理器中,只有MRS指令可以將狀態(tài)寄存器CPSR或SPSR讀出到通用寄存器中。
指令的語法格式:
MRS{cond} Rd,PSR
其中,Rd為目標寄存器,Rd不允許為程序計數(shù)器(PC)。PSR為CPSR或SPSR。
指令舉例:
MRS R1,CPSR ;將CPSR狀態(tài)寄存器讀取,保存到R1中
MRS R2,SPSR ;將SPSR狀態(tài)寄存器讀取,保存到R1中
MRS指令讀取CPSR,可用來判斷ALU的狀態(tài)標志及IRQ/FIQ中斷是否允許等;在異常處理程序中,讀SPSR可指定進入異常前的處理器狀態(tài)等。MRS與MSR配合使用,實現(xiàn)CPSR或SPSR寄存器的讀—修改—寫操作,可用來進行處理器模式切換,允許/禁止IRQ/FIQ中斷等設(shè)置。另外,進程切換或允許異常中斷嵌套時,也需要使用MRS指令讀取SPSR狀態(tài)值并保存起來。
MSR
在ARM處理器中,只有MSR指令可以直接設(shè)置狀態(tài)寄存器CPSR或SPSR。
指令的語法格式:
MSR{cond} PSR_field,#immed_8r
MSR{cond} PSR_field,Rm
其中,PSR是指CPSR或SPSR。<fields>設(shè)置狀態(tài)寄存器中需要操作的位。狀態(tài)寄存器的32位可以分為4個8位的域(field)。bits[31:24]為條件標志位域,用f表示;bits[23:16]為狀態(tài)位域,用s表示;bits[15:8]為擴展位域,用x表示;bits[7:0]為控制位域,用c表示;immed_8r為要傳送到狀態(tài)寄存器指定域的立即數(shù),8位;Rm為要傳送到狀態(tài)寄存器指定域的數(shù)據(jù)源寄存器。
指令舉例:
MSR CPSR_c,#0xD3 ;CPSR[7:0]=0xD3,切換到管理模式
MSR CPSR_cxsf,R3 ;CPSR=R3
注意:
只有在特權(quán)模式下才能修改狀態(tài)寄存器。
程序中不能通過MSR指令直接修改CPSR中的T位控制位來實現(xiàn)ARM狀態(tài)/Thumb狀態(tài)的切換,必須使用BX指令來完成處理器狀態(tài)的切換(因為BX指令屬轉(zhuǎn)移指令,它會打斷流水線狀態(tài),實現(xiàn)處理器狀態(tài)的切換)。MRS與MSR配合使用,實現(xiàn)CPSR或SPSR寄存器的讀—修改—寫操作,可用來進行處理器模式切換及允許/禁止IRQ/FIQ中斷等設(shè)置。
程序狀態(tài)寄存器指令的應用
【舉例】 使能IRQ中斷。
ENABLE_IRQ:
MRS R0,CPSR
BIC R0,R0,#0x80
MSR CPSR_c,R0
MOV PC,LR
【舉例】 禁止IRQ中斷。
DISABLE_IRQ:
MRS R0,CPSR
ORR R0,R0,#0x80
MSR CPSR_c,R0
MOV PC,LR
【舉例】 堆棧指令初始化。
INITSTACK:
MOV R0,LR ;保存返回地址
設(shè)置管理模式堆棧:
MSR CPSR_c,#0xD3
LDR SP,StackSvc
設(shè)置中斷模式堆棧:
MSR CPSR_c,#0xD2
LDR SP,StackSvc
協(xié)處理器指令
ARM體系結(jié)構(gòu)允許通過增加協(xié)處理器來擴展指令集。最常用的協(xié)處理器是用于控制片上功能的系統(tǒng)協(xié)處理器。例如,控制Cache和存儲管理單元的cp15寄存器。此外,還有用于浮點運算的浮點ARM協(xié)處理器,各生產(chǎn)商還可以根據(jù)需要開發(fā)自己的專用協(xié)處理器。
ARM協(xié)處理器具有自己專用的寄存器組,它們的狀態(tài)由控制ARM狀態(tài)的指令的鏡像指令來控制。程序的控制流指令由ARM處理器來處理,所有協(xié)處理器指令只能同數(shù)據(jù)處理和數(shù)據(jù)傳送有關(guān)。按照RISC的Load/Store體系原則,數(shù)據(jù)的處理和傳送指令是被清楚分開的,所以它們有不同的指令格式。ARM處理器支持16個協(xié)處理器,在程序執(zhí)行過程中,每個協(xié)處理器忽略ARM和其他協(xié)處理器指令。當一個協(xié)處理器硬件不能執(zhí)行屬于它的協(xié)處理器指令時,將產(chǎn)生一個未定義指令異常中斷,在該異常中斷處理過程中,可以通過軟件仿真該硬件操作。如果一個系統(tǒng)中不包含向量浮點運算器,則可以選擇浮點運算軟件包來支持向量浮點運算。
ARM協(xié)處理器可以部分地執(zhí)行一條指令,然后產(chǎn)生中斷。如除法運算除數(shù)為0和溢出,這樣可以更好地處理運行時產(chǎn)生(run-time-generated)的異常。但是,指令的部分執(zhí)行是由協(xié)處理器完成的,此過程對ARM來說是透明的。當ARM處理器重新獲得執(zhí)行時,它將從產(chǎn)生異常的指令處開始執(zhí)行。對某一個協(xié)處理器來說,并不一定用到協(xié)處理器指令中的所有的域。具體協(xié)處理器如何定義和操作完全由協(xié)處理器的制造商自己決定,因此,ARM協(xié)處理器指令中的協(xié)處理器寄存器的標識符及操作助記符也有各種不同的實現(xiàn)定義。程序員可以通過宏定義這些指令的語法格式。
ARM協(xié)處理器指令可分為以下3類。
協(xié)處理器數(shù)據(jù)操作。協(xié)處理器數(shù)據(jù)操作完全是協(xié)處理器內(nèi)部操作,它完成協(xié)處理器寄存器的狀態(tài)改變。如浮點加運算,在浮點協(xié)處理器中兩個寄存器相加,結(jié)果放在第3個寄存器中。這類指令包括CDP指令。
協(xié)處理器數(shù)據(jù)傳送指令。這類指令從寄存器讀取數(shù)據(jù)裝入?yún)f(xié)處理器寄存器,或?qū)f(xié)處理器寄存器的數(shù)據(jù)裝入存儲器。因為協(xié)處理器可以支持自己的數(shù)據(jù)類型,所以每個寄存器傳送的字數(shù)與協(xié)處理器有關(guān)。ARM處理器產(chǎn)生存儲器地址,但傳送的字節(jié)由協(xié)處理器控制。這類指令包括LDC指令和STC指令。
協(xié)處理器寄存器傳送指令。在某些情況下,需要ARM處理器和協(xié)處理器之間傳送數(shù)據(jù)。如一個浮點運算協(xié)處理器,F(xiàn)IX指令從協(xié)處理器寄存器取得浮點數(shù)據(jù),將它轉(zhuǎn)換為整數(shù),并將整數(shù)傳送到ARM寄存器中。經(jīng)常需要用浮點比較產(chǎn)生的結(jié)果來影響控制流,因此,比較結(jié)果必須傳送到ARM的CPSR中。這類協(xié)處理器寄存器傳送指令包括MCR和MRC。
如表所示列出了所有協(xié)處理器處理指令。
助 記 符操 作CDP協(xié)處理器數(shù)據(jù)操作LDC裝載協(xié)處理器寄存器MCR從ARM寄存器傳數(shù)據(jù)到協(xié)處理器寄存器MRC從協(xié)處理器寄存器傳數(shù)據(jù)到ARM寄存器STC存儲協(xié)處理器寄存器
下面簡單介紹一下比較常用的MCR及MRC命令的用法:
ARM寄存器到協(xié)處理器寄存器的數(shù)據(jù)傳送指令MCR
指令編碼格式
ARM寄存器到協(xié)處理器寄存器的數(shù)據(jù)傳送指令MCR(Move to Coprocessor from ARM Register)將ARM寄存器<Rd> 的值傳送到協(xié)處理器寄存器cp_num中。如果沒有協(xié)處理器執(zhí)行指定操作,將產(chǎn)生未定義指令異常。指令的編碼格式如圖所示。
指令的語法格式
MCR{<cond>} <coproc>,<opcode_1>,<Rd>,<CRn>,<CRm> {<opcode_2>}
① <cond>
為指令編碼中的條件域。它指示指令在什么條件下執(zhí)行。當<cond>忽略時,指令為無條件執(zhí)行(cond=AL(Alway ))。
② <coproc>
指定協(xié)處理器的編號,標準的協(xié)處理器的名字為p0、p1、…、p15。
③ <opcode_1>
指定協(xié)處理器執(zhí)行的操作碼,確定哪一個協(xié)處理器指令將被執(zhí)行。
④ <Rd>
確定哪一個ARM寄存器的數(shù)值將被傳送。如果程序計數(shù)器PC的值被傳送,指令的執(zhí)行結(jié)果不可預知。
⑤ <CRn>
確定包含第一個操作數(shù)的協(xié)處理器寄存器。
⑥ <CRm>
確定包含第二個操作數(shù)的協(xié)處理器寄存器。
⑦ <opcode_2>
指定協(xié)處理器執(zhí)行的操作碼,確定哪一個協(xié)處理器指令將被執(zhí)行。通常與<opcode_1>配合使用。
指令舉例
將ARM寄存器r7中的值傳送到協(xié)處理器p14的寄存器c7中,第一操作數(shù)opcode_1=1,第二操作數(shù)opcode_2=6。
MCR p14,1,r7,c7,c12 ,6
指令的使用
指令的編碼格式中,bits[31∶24]、bit[20]、bits[15∶8]和bit[4]為ARM體系結(jié)構(gòu)定義。其他域由各生產(chǎn)商定義。硬件協(xié)處理器支持與否完全由生產(chǎn)商定義,某款ARM芯片中,是否支持協(xié)處理器或支持哪個協(xié)處理器與ARM版本無關(guān)。生產(chǎn)商可以選擇實現(xiàn)部分協(xié)處理器指令或者完全不支持協(xié)處理器。
協(xié)處理器寄存器到ARM寄存器的數(shù)據(jù)傳送指令MRC
指令編碼格式
協(xié)處理器寄存器到ARM寄存器的數(shù)據(jù)傳送指令MRC(Move to ARM register from Coprocessor)將協(xié)處理器cp_num 的寄存器的值傳送到ARM寄存器中。如果沒有協(xié)處理器執(zhí)行指定操作,將產(chǎn)生未定義指令異常。指令的編碼格式如圖所示。
指令的語法格式
MRC{<cond>} <coproc>,<opcode_1>,<Rd>,<CRn>,<CRm>{,<opcode_2>}
為指令編碼中的條件域。它指示指令在什么條件下執(zhí)行。當<cond>忽略時,指令為無條件執(zhí)行(cond=AL(Alway ))。
① <coproc>
指定協(xié)處理器的編號,標準的協(xié)處理器的名字為p0、p1、…、p15。
② <opcode_1>
指定協(xié)處理器執(zhí)行的操作碼,確定哪一個協(xié)處理器指令將被執(zhí)行。
③ <Rd>
確定哪一個ARM寄存器接受協(xié)處理器傳送的數(shù)值。如果程序計數(shù)器PC被用做目的寄存器,指令的執(zhí)行結(jié)果不可預知 。
④ <CRn>
確定包含第一個操作數(shù)的協(xié)處理器寄存器。
⑤ <CRm>
確定包含第二個操作數(shù)的協(xié)處理器寄存器。
⑥ <opcode_2>
指定協(xié)處理器執(zhí)行的操作碼,確定哪一個協(xié)處理器指令將被執(zhí)行。通常與<opcode_1>配合使用。
指令舉例
協(xié)處理器源寄存器為c0和c2,目的寄存器為ARM寄存器r4,第一操作數(shù)opcode_1=5,第二操作數(shù)opcode_2=3。
MRC p15,5,r4,c0,c2,3
指令的使用
如果目的寄存器為程序計數(shù)器r15,則程序狀態(tài)字條件標準位根據(jù)傳送數(shù)據(jù)的前4bit確定,后28bit被忽略。指令的編碼格式中,bits[31:24]、bit[20]、bits[15:8]和bit[4]為ARM體系結(jié)構(gòu)定義。其他域由各生產(chǎn)商定義。
硬件協(xié)處理器支持與否完全由生產(chǎn)商定義,某款ARM芯片中,是否支持協(xié)處理器或支持哪個協(xié)處理器與ARM版本無關(guān)。生產(chǎn)商可以選擇實現(xiàn)部分協(xié)處理器指令或者完全不支持協(xié)處理器。
如果協(xié)處理器必須完成一些內(nèi)部工作來準備一個32位數(shù)據(jù)向ARM傳送(例如,浮點FIX操作必須將浮點值轉(zhuǎn)換為等效的定點值),那么這些工作必須在協(xié)處理器提交傳送前進行。因此,在準備數(shù)據(jù)時經(jīng)常需要協(xié)處理器握手信號處于“忙-等待”狀態(tài)。ARM可以在忙-等待時間內(nèi)產(chǎn)生中斷。如果它確實得以中斷,那么它將暫停握手以服務中斷。當它從中斷服務程序返回時,將可能重試協(xié)處理器指令,但也可能不重試。例如,中斷可能導致任務切換,無論哪種情況,協(xié)處理器必須給出一致結(jié)果,因此,在握手提交階段之前的準備工作不允許改變處理器的可見狀態(tài)。
如圖所示列出了cp15的各個寄存器的目的。

異常產(chǎn)生指令
ARM指令集中提供了兩條產(chǎn)生異常的指令,通過這兩條指令可以用軟件的方法實現(xiàn)異常。如表所示為ARM異常產(chǎn)生指令。
助 記 符含 義操 作SWI軟中斷指令產(chǎn)生軟中斷,處理器進入管理模式BKPT斷點中斷指令處理器產(chǎn)生軟件斷點
軟件中斷指令(Software Interrupt,SWI)用于產(chǎn)生軟中斷,從而實現(xiàn)從用戶模式變換到管理模式,CPSR保存到管理模式的SPSR中,執(zhí)行轉(zhuǎn)移到SWI向量,在其他模式下也可以使用SWI指令,處理器同樣切換到管理模式。
指令的語法格式。
SWI{<cond>} <immed_24>
指令舉例。
① 下面指令產(chǎn)生軟中斷,中斷立即數(shù)為0。
SWI 0;
② 產(chǎn)生軟中斷,中斷立即數(shù)為0x123456。
SWI 0x123456;
③ 使用SWI指令時,通常使用以下兩種方法進行參數(shù)傳遞。
a.指令24位的立即數(shù)指定了用戶請求的類型,中斷服務程序的參數(shù)通過寄存器傳遞。
下面的程序產(chǎn)生一個中斷號為12的軟中斷。
MOV R0,#34 ;設(shè)置功能號為34
SWI 12 ;產(chǎn)生軟中斷,中斷號為12
b.另一種情況,指令中的24位立即數(shù)被忽略,用戶請求的服務類型由寄存器R0的值決定,參數(shù)通過其他寄存器傳遞。
下面的例子通過R0傳遞中斷號,R1傳遞中斷的子功能號。
MOV R0,#12 ;設(shè)置12號軟中斷
MOV R1,#34 ;設(shè)置功能號為34
SWI 0
其他指令介紹
特殊指令介紹
Fmxr /Fmrx指令是NEON下的擴展指令,在做浮點運算的時候,要先打開vfp,因此需要用到Fmxr指令。
Fmxr:由arm寄存器將數(shù)據(jù)轉(zhuǎn)移到協(xié)處理器中。
Fmrx:由協(xié)處理器轉(zhuǎn)移到arm寄存器中。
如圖所示為浮點異常寄存器格式。

如表所示為FPEXC的位定義。
位域功能描述[31]EX異常位,該位指定了有多少信息需要存儲記錄SIMD/VFP協(xié)處理器的狀態(tài)[30]ENNEON/VFP使能位,設(shè)置EN位1則開啟NEON/VFP協(xié)處理器,復位會將EN置0[29:0]保留
FPEXC<浮點異常寄存器>,該寄存器是一個可控制SIMD及VFP的全局使能寄存器,并指定了這些擴展技術(shù)是如何記錄的。
如果要打開VFP協(xié)處理器的話,可以用以下指令:
mov r0, #0x40000000
fmxr fpexc, r0 @ enable NEON and VFP coprocessor
CLZ 計算前導零數(shù)目
語法格式:
CLZ {cond} Rd,Rm
其中:
cond 是一個可選的條件代碼。
Rd是目標寄存器。
Rm 是操作數(shù)寄存器。
用法:CLZ指令對Rm中的值的前導零進行計數(shù),并將結(jié)果返回到Rd中,如果未在源寄存器中設(shè)置任何位,則該結(jié)果值為32,如果設(shè)置了位31,則結(jié)果值為0。
條件標記:該指令不會更改標記。
體系結(jié)構(gòu):ARMv5 以上。
示例如圖所示。
飽和指令介紹
這是用來設(shè)計飽和算法的一組指令,所謂飽和是指出現(xiàn)下列3種情況:
對于有符號飽和運算,如果結(jié)果小于-2n,則返回結(jié)果將為-2n。
對于無符號飽和運算,如果整數(shù)結(jié)果是負值,那么返回的結(jié)果將為0。
對于結(jié)果大于2n -1的情況,則返回結(jié)果將為2n -1。
只要出現(xiàn)這情況,就稱為飽和,并且飽和指令會設(shè)置Q標記,下面簡單介紹一下QADD帶符號加法。
QSUB:帶符號減法。
QDADD:帶符號加倍加法。
QDSUB:帶符號加倍減法。
將結(jié)果飽和導入符號范圍(-231≤x ≤231-1)內(nèi)。
語法格式:
op{cond} {Rd} ,Rm,Rn
其中:
op 是QADD,QSUB,QDADD,QDSUB之一。
cond 是一個可選的條件代碼。
Rd 是目標寄存器。
Rm, Rn 是存放操作數(shù)的寄存器(注:不要將r15用做Rd,Rm或Rn)。
用法如下:
QADD指令可將Rm和Rn中的值相加。
QSUB指令可從Rm中的值減去Rn中的值。
QDADD/QDSUB指令涉及并行指令,因此這里不多做討論。
條件標記:如果發(fā)生飽和,則這些指令設(shè)置Q標記,若要讀取Q標記的狀態(tài),需要使用MRS指令。
體系結(jié)構(gòu):該指令可用于v5T-E及v6或者更高版本的體系中。
示例如下:
QADD r0 ,r1,r9
QSUBLT r9,r0,r1
ARM 匯編實驗
實驗目的
掌握 ARM匯編語言的基本使用;
熟悉 eclipse 開發(fā)工具建立匯編工程和仿真;
實驗原理
根據(jù)上面闡述RAM 匯編語言的使用語法和功能,編寫匯編程序,實現(xiàn)一個簡單的數(shù)據(jù)運算操作。
實驗內(nèi)容
匯編程序設(shè)計如下
.text
.global _start
_start:
mov r0, #0x9
nop
mov r1, #0x7
loop:
bl add_sub
stop:
b stop
add_sub:
add r2, r0, r1
sub r3, r0, r1
mul r4, r0,r1
mov pc, lr
實驗步驟
導入工程源碼
請參考第37章的導入已有工程章節(jié)。
光盤實驗源碼路徑:【資料光盤\華清遠見-FS-MP1A開發(fā)資料-2020-11-06\02-程序源碼\03-ARM體系結(jié)構(gòu)與接口技術(shù)\Cortex-A7\h_project】
打開“Register”顯示框
單擊window -> show view -> Register,

單步仿真
配置完成之后,點擊“

”開始仿真,彈出Debug框。

單擊“

”單步仿真。查看仿真現(xiàn)象。
實驗現(xiàn)象
單擊“

”單步,查看Rn寄存器的變化。


單步運行可以看到R2、R3和R4的值變化。
硬件平臺:華清遠見FS-MP1A開發(fā)板(STM32MP157)
部分開發(fā)教程下載:加QQ群483143191,群文件里有。
部分視頻課程收看:華清遠見研發(fā)中心的個人空間_嗶哩嗶哩_Bilibili
淘寶購買鏈接:https://item.taobao.com/item.htm?id=622457259672
手機淘寶分享碼:復制本行文字打開手淘?T4FPXn3YYJ2?