最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

基于stm32mp157 linux開發(fā)板ARM裸機(jī)開發(fā)教程5:ARM微處理器指令系統(tǒng)(連載中)

2023-04-14 13:43 作者:華清遠(yuǎn)見研發(fā)中心  | 我要投稿

前言:

目前針對ARM Cortex-A7裸機(jī)開發(fā)文檔及視頻進(jìn)行了二次升級持續(xù)更新中,使其內(nèi)容更加豐富,講解更加細(xì)致,全文所使用的開發(fā)平臺均為華清遠(yuǎn)見FS-MP1A開發(fā)板(STM32MP157開發(fā)板)

針對對FS-MP1A開發(fā)板,除了Cortex-A7裸機(jī)開發(fā)篇外,還包括其他多系列教程,包括Cortex-M4開發(fā)篇、FreeRTOS篇、Linux基礎(chǔ)及應(yīng)用開發(fā)篇、Linux系統(tǒng)移植篇、Linux驅(qū)動開發(fā)篇、硬件設(shè)計(jì)篇、人工智能機(jī)器視覺篇、Qt應(yīng)用編程篇、Qt綜合項(xiàng)目實(shí)戰(zhàn)篇等。除此之外計(jì)劃針對Linux系統(tǒng)移植篇、Linux驅(qū)動開發(fā)篇均會進(jìn)行文檔及視頻的二次升級更新敬請關(guān)注!

開發(fā)板更多資料可關(guān)注華清遠(yuǎn)見在線實(shí)驗(yàn)室(微信號:hqyjlab)領(lǐng)取~~~

ARM 微處理器指令系統(tǒng)

ARM 指令集可以分為跳轉(zhuǎn)指令、數(shù)據(jù)處理指令、程序狀態(tài)寄存器傳輸指令、Load/Store 指令、協(xié)處理

器指令和異常中斷產(chǎn)生指令。根據(jù)使用的指令類型不同,指令的尋址方式分為數(shù)據(jù)處理指令尋址方式和內(nèi)存訪問指令尋址方式。

本章主要介紹 ARM 匯編語言。主要內(nèi)容如下:

? ARM 處理器的尋址方式。

? ARM 處理器的指令集

ARM 指令的組成

<opcode> {<c>} {S} <Rd>,<Rn>,<shifter_operand>

指令解析:

<opcode>: 要執(zhí)行的指令

{<c>}: 為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

表 44.7.2.1 指令執(zhí)行條件

{S}: 決定指令的操作是否影響 CPSR。在異常返回時(shí),如果操作的目標(biāo)是 PC 寄存器時(shí),S 標(biāo)志會同

時(shí)將 SPSR 寄存器恢復(fù)到 CPSR 中。

<Rd>: 為目標(biāo)寄存器。

<Rn>: 操作數(shù)所在的寄存器。

<shifter_operand>有 11 種形式,如表所示

以下是關(guān)于 MOV 指令的一些示例:

示例代碼 45-1 示例

1 MOV R0,#2

2 ADDS R0,R0,R1

3 MOV R2,R0

4 MOV R1, R0, LSL #2

ARM 處理器尋址方式

ARM 指令的尋址方式分為數(shù)據(jù)處理指令尋址方式和內(nèi)存訪問指令尋址方式。

數(shù)據(jù)處理指令尋址方式

數(shù)據(jù)處理指令尋址方式可以分為以下幾種。

? 立即數(shù)尋址方式。

? 寄存器尋址方式。

? 寄存器移位尋址方式。

1、 立即數(shù)尋址方式

指令中的立即數(shù)是由一個(gè) 8bit 的常數(shù)移動 4bit 偶數(shù)位(0,2,4,…,26,28,30)得到的。所以,每一條指令都包含一個(gè) 8bit 的常數(shù) X 和移位值 Y,得到的立即數(shù) = X 循環(huán)右移(2×Y),如圖所示。

立即數(shù)為什么需要通過上述運(yùn)算得到呢?這里我們以 ldr 指令的機(jī)器碼為例來分析原因。

上圖中 imm12 就是立即數(shù)所占用的位域,在這里可以看到 imm12 的區(qū)域只有 12bit,要用一個(gè) 12bit

的編碼來表示任意的 32bit 數(shù)是絕對不可能的。而然在實(shí)際的開發(fā)過程中又要用 12bit 的編碼來表示 32bit

數(shù)。那么只有在表示數(shù)的數(shù)量上做限制,通過編碼來實(shí)現(xiàn)用 12bit 的編碼來表示 32bit 數(shù)。

在上面我們提到了立即數(shù) = X 循環(huán)右移(2×Y),盡管表示的范圍變大了, 但是 12 位所能表現(xiàn)的數(shù)字的個(gè)數(shù)是一定的. 因此, ARM 規(guī)定并不是所有的 32 位常數(shù)都是合法的立即數(shù), 只有通過上面的構(gòu)造方法得到的才是合法的立即數(shù)。

ARM 匯編編譯器按照下面的規(guī)則來產(chǎn)生立即數(shù)的編碼:

當(dāng)立即數(shù)數(shù)值在 0~0xFF 范圍時(shí),令 X=立即數(shù),Y=0。

其他情況下,匯編編譯器選擇使 Y 數(shù)值最小的編碼方式。

則來產(chǎn)生立即數(shù)的編碼:

下面列舉了一些有效的立即數(shù):

0xFF:X=0xFF,Y=0

0x104:X=0x41,Y=15

0xFF0:X=0xFF,Y=14

0xF000000F:X=0xFF,Y=2

下面是一些無效的立即數(shù):

0x101、0x102、0xFF1、0xFF04、0xFF003、0xFFFFFFFF、0xF000001F

下面是一些應(yīng)用立即數(shù)的指令

示例代碼 45-2 立即數(shù)

1 MOV R0,#0 ;送0到R0

2 ADD R3,R3,#1 ;R3的值加1

3 CMP R7,#1000 ;將R7的值和1000比較

4 BIC R9,R8,#0xFF00 ;將 R8 中 8~15 位清零,結(jié)果保存在 R9 中

2、 寄存器尋址方式

寄存器的值可以被直接用于數(shù)據(jù)操作指令,這種尋址方式是各類處理器經(jīng)常采用的一種方式,也是一種執(zhí)行效率較高的尋址方式,如:

示例代碼 45-3 寄存器尋址

1 MOV R2,R0 ;R0的值送R2

2 ADD R4,R3,R2 ;R2加R3,結(jié)果送R4

3 CMP R7,R8 ;比較 R7 和 R8 的值


3、 寄存器移位尋址方式

和寄存器尋址類似,只是操作前需要對寄存器操作數(shù)進(jìn)行移位操作。寄存器的值在被送到 ALU 之前,可以事先經(jīng)過桶形移位寄存器的處理。預(yù)處理和移位發(fā)生在同一周期內(nèi),所以有效地使用移位寄存器,可以增加代碼的執(zhí)行效率。

LSL<c> <Rd>, <Rm>, #<imm5>

LSR<c> <Rd>, <Rm>, #<imm>

ASR<c> <Rd>, <Rm>, #<imm>

ROR{S}<c> <Rd>, <Rm>, #<imm>

RRX{S}<c> <Rd>, <Rm>

{<c>}: 為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

<Rd>: 為目標(biāo)寄存器。

<Rm>: 操作數(shù)所在的寄存器。

<imm>: 移位量,范圍 1-32。

帶擴(kuò)展的循環(huán)右移(RRX): 操作數(shù)右移一位,移位空出的高位用 C 標(biāo)志的值填充。

下面是一些在指令中使用了移位操作的例子:

示例代碼 45-4 寄存器移位尋址

1 ADD R2, R0, R1, LSR #5 ;將R1的值邏輯右移5位后與R0相加結(jié)果傳入R2

2 MOV R1, R0, LSL #2 ;將R0的值邏輯左移2位后將結(jié)果傳入R1

3 SUB R1, R2, R0, LSR #4 ;用R2的值減去將R0的值邏輯右移4位后的值將結(jié)果傳入R1

4 MOV R2, R4, ROR R0 ;將R4的值循環(huán)右移R0次,結(jié)果傳入R2

內(nèi)存訪問指令尋址方式

內(nèi)存訪問指令的尋址方式可以分為以下幾種。

? 字及無符號字節(jié)的 Load/Store 指令的尋址方式。

? 雜類 Load/Store 指令的尋址方式。

? 批量 Load/Store 指令的尋址方式。

? 協(xié)處理器 Load/Store 指令的尋址方式。

1、 字及無符號字節(jié)的 Load/Store 指令的尋址方式

字及無符號字節(jié)的 Load/Store 指令語法格式如下:

LDR|STR{<cond>}{B}{T} <Rd>,<addressing_mode>

上表中,“!”表示完成數(shù)據(jù)傳輸后要更新基址寄存器。

2、 雜類 Load/Store 指令的尋址方式

使用該類尋址方式的指令的語法格式如下:

LDR|STR{<cond>}H|SH|SB|D <Rd>, <addressing_mode>

使用該類尋址方式的指令包括(有符號/無符號)半字 Load/Store 指令、有符號字節(jié) Load/Store 指令和雙字 Load/Store 指令。

表 45.2.2.2 <addressing_mode>尋址方式

3、 堆棧操作尋址方式

堆棧操作尋址方式和批量 Load/Store 指令尋址方式十分類似。但對于堆棧的操作,數(shù)據(jù)寫入內(nèi)存和從內(nèi)存中讀出要使用不同的尋址模式,因?yàn)檫M(jìn)棧操作(pop)和出棧操作(push)要在不同的方向上調(diào)整堆棧。

該類指令的語法格式如下:

LDM|STM {<amode>}{<cond>}<addressing_mode> <Rn>{!},<registers><^>

下面詳細(xì)討論如何使用合適的尋址方式實(shí)現(xiàn)數(shù)據(jù)的堆棧操作。

根據(jù) amode 不同的尋址方式,將堆棧分為以下 4 種。

1) 滿棧:堆棧指針指向棧頂元素(last used location)。

2) 空棧:堆棧指針指向第一個(gè)可用元素(the first unused location)。

3) 遞減棧:堆棧向內(nèi)存地址減小的方向生長。

4) 遞增棧:堆棧向內(nèi)存地址增加的方向生長。

根據(jù)堆棧的不同種類,將其尋址方式分為以下 4 種。

1) 滿遞減 FD(Full Descending)。

2) 空遞減 ED(Empty Descending)。

3) 滿遞增 FA(Full Ascending)。

4) 空遞增 EA(Empty Ascending)。

如表所示列出了堆棧的尋址方式和批量 Load/Store 指令尋址方式的對應(yīng)關(guān)系。

批量 Load/Store 指令尋址方式

批量 Load/Store 指令將一片連續(xù)內(nèi)存單元的數(shù)據(jù)加載到通用寄存器組中或?qū)⒁唤M通用寄存器的數(shù)據(jù)存儲到內(nèi)存單元中。

批量 Load/Store 指令的尋址模式產(chǎn)生一個(gè)內(nèi)存單元的地址范圍,指令寄存器和內(nèi)存單元的對應(yīng)關(guān)系滿足這樣的規(guī)則,即編號低的寄存器對應(yīng)于內(nèi)存中低地址單元,編號高的寄存器對應(yīng)于內(nèi)存中的高地址單元。

該類指令的語法格式如下:

LDM|STM {<amode>}{<cond>}<addressing_mode> <Rn>{!},<registers><^>

協(xié)處理器 Load/Store 尋址方式

協(xié)處理器 Load/Store 指令的語法格式如下:

MCR<c> <coproc>, <opc1>, <Rt>, <CRn>, <CRm>{, <opc2>}

MRC<c> <coproc>, <opc1>, <Rt>, <CRn>, <CRm>{, <opc2>}

<c>:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行

<coproc>:協(xié)處理器名稱,范圍 p0-p15;

<opc1>:協(xié)處理器操作碼,范圍 0-15;

<Rt>:源寄存器,MCR 指令是將 Rt 寄存器寫入?yún)f(xié)處理器,MRC 指令是將協(xié)處理器的內(nèi)容讀取到 Rt 寄存器;

<CRn>:協(xié)處理器的目標(biāo)寄存器;

<CRm>:協(xié)處理器中附加的目標(biāo)寄存器或者源操作寄存器,如果不需要附加信息就設(shè)置為 C0,否則結(jié)果不可預(yù)測;

<opc2>:可選的協(xié)處理器特定操作碼,當(dāng)不需要時(shí)置 0。

關(guān)于 CRn、opc1、CRm、opc2 等操作,以下給出了 CP15 協(xié)處理器的寄存器排布。操作不同的協(xié)處理器時(shí)對應(yīng)著不同的取值

例如前面講到的 Cache 操作指令

示例代碼 45-5 使能 ICache

1 /******Cache Test*******/

2 mrc p15,0,r1,c1,c0,0

3 orr r1, r1, #(1 << 2) // Set C bit 整體使能Cache

4 orr r1, r1, #(1 << 12) //Set I bit 使能ICache

5 mcr p15,0,r1,c1,c0,0

6 /******End Test******/

如果需要操作其它協(xié)處理器可以通過查閱《ARM? Architecture Reference Manual》或者《Cortex-A7 MPCore Technical Reference Manual》官方文檔進(jìn)行查閱。

ARM 處理器指令集

數(shù)據(jù)操作指令

數(shù)據(jù)操作指令是指對存放在寄存器中的數(shù)據(jù)進(jìn)行操作的指令。主要包括數(shù)據(jù)傳送指令、算術(shù)指令、邏輯指令、比較與測試指令及乘法指令。

如果在數(shù)據(jù)處理指令前使用 S 前綴,指令的執(zhí)行結(jié)果將會影響 CPSR 中的標(biāo)志位。數(shù)據(jù)處理指令如表所示。

1、 MOV 指令

MOV 指令是最簡單的 ARM 指令,執(zhí)行的結(jié)果就是把一個(gè)數(shù) N 送到目標(biāo)寄存器 Rd,其中 N 可以是寄存器,也可以是立即數(shù)。

MOV 指令多用于設(shè)置初始值或者在寄存器間傳送數(shù)據(jù)。

MOV 指令將移位碼(shifter_operand)表示的數(shù)據(jù)傳送到目的寄存器 Rd,并根據(jù)操作的結(jié)果更新 CPSR中相應(yīng)的條件標(biāo)志位。

指令的語法格式:

MOV{<c>}{S} <Rd>,<shifter_operand>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rd>:目的寄存器。如果 R15 是目的寄存器,將修改程序計(jì)數(shù)器或標(biāo)志。這用于被調(diào)用的子函數(shù)結(jié)束后返回到調(diào)用代碼,方法是把連接寄存器的內(nèi)容傳送到 R15。

<shifter_operand>:要傳送到 Rd 寄存器的數(shù)據(jù),可以是立即數(shù)、寄存器或者通過移位操作得到指令舉例:

示例代碼 45-6 mov 示例

1 mov r0, r0 ; R0=R0 NOP 指令

2 mov r0, r0, lsl#3 ; R0=R0*8

3 mov pc, lr ; 退出到調(diào)用者,用于普通函數(shù)返回,PC即是R15

4 movs pc, lr ; 退出到調(diào)用者并恢復(fù)標(biāo)志位,用于異常函數(shù)返回

MOV 指令主要完成以下功能。

? 將數(shù)據(jù)從一個(gè)寄存器傳送到另一個(gè)寄存器。

? 將一個(gè)常數(shù)值傳送到寄存器中。

? 當(dāng) PC(R15)用做目的寄存器時(shí),可以實(shí)現(xiàn)程序跳轉(zhuǎn)。如“MOV PC,LR”,所以這種跳轉(zhuǎn)可以實(shí)現(xiàn)子程序調(diào)用及從子程序返回,代替指令“B,BL”。

? 當(dāng) PC 作為目標(biāo)寄存器且指令中 S 位被設(shè)置時(shí),指令在執(zhí)行跳轉(zhuǎn)操作的同時(shí),將當(dāng)前處理器模式的 SPSR 寄存器的內(nèi)容復(fù)制到 CPSR 中。這種指令“MOVS PC LR”可以實(shí)現(xiàn)從某些異常中斷中返回。

MVN 指令

MVN 是反相傳送(Move Negative)指令。它將操作數(shù)的反碼傳送到目的寄存器。

MVN 指令多用于向寄存器傳送一個(gè)負(fù)數(shù)或生成位掩碼。

MVN 指令將 shifter_operand 表示的數(shù)據(jù)的反碼傳送到目的寄存器 Rd,并根據(jù)操作結(jié)果更新 CPSR 中相應(yīng)的條件標(biāo)志位。

指令的語法格式:

MVN{<c>}{S} <Rd>,<shifter_operand>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rd>:目的寄存器。

<shifter_operand>:要傳送到 Rd 寄存器的數(shù)據(jù),可以是立即數(shù)、寄存器或者通過移位操作得到。這是邏輯非操作而不是算術(shù)操作,這個(gè)取反的值加 1 才是它的取負(fù)的值。

指令舉例:

示例代碼 45-7 mvn 示例

1 mvn r0, #4 ; r0 = -5

2 mvn r0, #0 ; r0 = -1

MVN 指令主要完成以下功能:

? 向寄存器中傳送一個(gè)負(fù)數(shù)。

? 生成位掩碼(Bit Mask)。

? 求一個(gè)數(shù)的反碼。

AND 指令

AND 指令將 shifter_operand 表示的數(shù)值與寄存器 Rn 的值按位(bitwise)做邏輯與操作,并將結(jié)果保存到目標(biāo)寄存器 Rd 中,同時(shí)根據(jù)操作的結(jié)果更新 CPSR 寄存器。

指令的語法格式:

AND{<c>}{S} <Rd>,<Rn>,<shifter_operand>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rd>:目的寄存器。

<Rn>:第一個(gè)操作數(shù)寄存器。

<shifter_operand>:要和 Rn 寄存器做與操作的數(shù)據(jù)

指令舉例:

示例代碼 45-8 and 示例

1 and r0, r0, #3 ;保留r0中的0位和1位,丟棄其余的位。

2 and r2,r1,r3 ;r2 = r1&r3

3 ands r0,r0,#0x01 ;r0 = r0&0x01,取出最低位數(shù)據(jù)

ORR 指令

ORR(Logical OR)為邏輯或操作指令,它將第 2 個(gè)源操作數(shù) shifter_operand 的值與寄存器 Rn 的值按位做“邏輯或”操作,結(jié)果保存到 Rd 中。

指令的語法格式:

ORR{<c>}{S} <Rd>,<Rn>,<shifter_operand>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rd>:目的操作數(shù)

<Rn>:第一個(gè)操作數(shù)。

<shifter_operand>:要與 Rn 做邏輯或的數(shù)

指令舉例:

示例代碼 45-9 orr 示例

1 orr r0, r0, #3 ;設(shè)置r0中位0和1

2 orr r0,r0,#0x0f ;將r0的低4位置1

3 ; 使用orr指令將r2的高8位數(shù)據(jù)移入到r3的低8位中。

4 mov r1,r2,lsr #4

5 orr r3,r1,r3,lsl #8

BIC 位清零指令

BIC(Bit Clear)位清零指令,將寄存器 Rn 的值與第 2 個(gè)源操作數(shù) shifter_operand 的值的反碼按位

做“邏輯與”操作,結(jié)果保存到 Rd 中。

指令的語法格式:

BIC{<c>}{S} <Rd>,<Rn>,<shifter_operand>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rd>:目的操作數(shù)

<Rn>:第一個(gè)操作數(shù)。

<shifter_operand>:取反碼與 Rn 做“邏輯與”操作

指令舉例:

示例代碼 45-10 bic 示例

1 bic r0, r0, #0x1011 ;清除r0中的位12、4和0位,保持其余的不變

2 bic r1, r2, r3 ;將 r3 和 r2 做“邏輯與”操作,結(jié)果保存到 r1 中

EOR 指令

EOR(Exclusive OR)指令將寄存器 Rn 中的值和 shifter_operand 的值執(zhí)行按位“異或”操作,并將執(zhí)行結(jié)果存儲到目的寄存器 Rd 中,同時(shí)根據(jù)指令的執(zhí)行結(jié)果更新 CPSR 中相應(yīng)的條件標(biāo)志位。

指令的語法格式:

EOR{<c>}{S} <Rd>,<Rn>,<shifter_operand>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rd>:目的寄存器。

<Rn>:第一個(gè)操作數(shù)寄存器。

<shifter_operand>:要和 Rn 寄存器做異或操作的數(shù)據(jù)

指令舉例:

示例代碼 45-11 eor 示例

1 eor r0, r0, #3 ;反轉(zhuǎn)r0中的位0和1

2 eor r1,r1,#0x0f ;將r1的低4位取反

3 eor r2,r1,r0 ;r2=r1∧r0

4 eors r0,r5,#0x01 ;r0=r5∧0x01 影響標(biāo)志位

SUB 指令

SUB(Subtract)指令從寄存器 Rn 中減去 shifter_operand 表示的數(shù)值,并將結(jié)果保存到目標(biāo)寄存器 Rd

中,并根據(jù)指令的執(zhí)行結(jié)果設(shè)置 CPSR 中相應(yīng)的標(biāo)志位。

指令的語法格式:

SUB{<c>}{S} <Rd>,<Rn>,<shifter_operand>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rd>:目的寄存器。

<Rn>:被減數(shù)。

<shifter_operand>:減數(shù)

指令舉例:

示例代碼 45-12 sub 示例

1 sub r0, r1, r2 ;r0 = r1?r2

2 sub r0, r1, #256 ;r0 = r1?256

3 sub r0, r2, r3,lsl#1 ;r0 = r2?(r3<<1)

RSB 指令

RSB(Reverse Subtract)指令從寄存器 shifter_operand 中減去 Rn 表示的數(shù)值,并將結(jié)果保存到目標(biāo)寄

存器 Rd 中,并根據(jù)指令的執(zhí)行結(jié)果設(shè)置 CPSR 中相應(yīng)的標(biāo)志位。

指令的語法格式:

RSB{<c>}{S} <Rd>,<Rn>,<shifter_operand>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rd>:目的寄存器。

<Rn>:減數(shù)。

<shifter_operand>:被減數(shù)

指令舉例:

下面的指令序列可以求一個(gè) 64 位數(shù)值的負(fù)數(shù)。64 位數(shù)放在寄存器 R0 與 R1 中,其負(fù)數(shù)放在 R2 和 R3中。其中 R0 與 R2 中放低 32 位值。

示例代碼 45-13 rsb 示例

1 rsbs r2,r0,#0

2 rsc r3,r1,#0

SBC 指令

SBC(Subtract with Carry)指令用于執(zhí)行操作數(shù)大于 32 位時(shí)的減法操作。該指令從寄存器 Rn 中減去shifter_operand 表示的數(shù)值,再減去寄存器 CPSR 中 C 條件標(biāo)志位的反碼[NOT(Carry flag)],并將結(jié)果保存到目標(biāo)寄存器 Rd 中,并根據(jù)指令的執(zhí)行結(jié)果設(shè)置 CPSR 中相應(yīng)的標(biāo)志位。

指令的語法格式:

SBC{<c>}{S} <Rd>,<Rn>,<shifter_operand>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rd>:目的寄存器。

<Rn>:被減數(shù)。

<shifter_operand>:減數(shù)

指令舉例:

下面的程序使用 SBC 實(shí)現(xiàn) 64 位減法,(R1,R0)?(R3,R2),結(jié)果存放到(R1,R0)。

示例代碼 45-14 sbc 示例

1 subs r0,r0,r2

2 sbcs r1,r1,r3

0、RSC 指令

RSC(Reverse Subtract with Carry)指令從寄存器 shifter_operand 中減去 Rn 表示的數(shù)值,再減去寄存器 CPSR 中 C 條件標(biāo)志位的反碼[NOT(Carry Flag)],并將結(jié)果保存到目標(biāo)寄存器 Rd 中,并根據(jù)指令的執(zhí)行結(jié)果設(shè)置 CPSR 中相應(yīng)的標(biāo)志位。

指令的語法格式:

RSC{<c>}{S} <Rd>,<Rn>,<shifter_operand>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rd>:目的寄存器。

<Rn>:減數(shù)。

<shifter_operand>:被減數(shù)

指令舉例:

下面的程序使用 RSC 指令實(shí)現(xiàn)求 64 位數(shù)值的負(fù)數(shù)。

示例代碼 45-15 rsc 示例

1 rsbs r2,r0,#0

2 rsc r3,r1,#0

ADD 指令

ADD 指令將寄存器 shifter_operand 的值加上 Rn 表示的數(shù)值,并將結(jié)果保存到目標(biāo)寄存器 Rd 中,并根據(jù)指令的執(zhí)行結(jié)果設(shè)置 CPSR 中相應(yīng)的標(biāo)志位。

指令的語法格式:

ADD{<c>}{S} <Rd>,<Rn>,<shifter_operand>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rd>:目的寄存器。

<Rn>:第一個(gè)操作數(shù)。

<shifter_operand>:要加的數(shù)

指令舉例:

示例代碼 45-16 add 示例

1 add r0, r1, r2 ; r0 = r1 + r2

2 add r0, r1, #256 ; r0 = r1 + 256

3 add r0, r2, r3,lsl#1 ; r0 = r2 + (r3 << 1)

ADC 指令

ADC 指令將寄存器 shifter_operand 的值加上 Rn 表示的數(shù)值,再加上 CPSR 中的 C 條件標(biāo)志位的值,將結(jié)果保存到目標(biāo)寄存器 Rd 中,并根據(jù)指令的執(zhí)行結(jié)果設(shè)置 CPSR 中相應(yīng)的標(biāo)志位。

指令的語法格式:

ADC{<c>}{S} <Rd>,<Rn>,<shifter_operand>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rd>:目的寄存器。

<Rn>:第一個(gè)操作數(shù)。

<shifter_operand>:要加的數(shù)

指令舉例:

ADC 指令將把兩個(gè)操作數(shù)加起來,并把結(jié)果放置到目的寄存器中。它使用一個(gè)進(jìn)位標(biāo)志位,這樣就可以做比 32 位大的加法。下面的例子將加兩個(gè) 128 位的數(shù)。

128 位結(jié)果:寄存器 R0、R1、R2 和 R3。

第一個(gè) 128 位數(shù):寄存器 R4、R5、R6 和 R7。

第二個(gè) 128 位數(shù):寄存器 R8、R9、R10 和 R11。

示例代碼 45-17 adc 示例

1 adds r0, r4, r8 ;加低端的字

2 adcs r1, r5, r9 ;加下一個(gè)字,帶進(jìn)位

3 adcs r2, r6, r10 ;加第三個(gè)字,帶進(jìn)位

4 adcs r3, r7, r11 ;加高端的字,帶進(jìn)位

CMP 指令

CMP(Compare)指令使用寄存器 Rn 的值減去 shifter_operand 的值,根據(jù)操作的結(jié)果更新 CPSR 中相應(yīng)的條件標(biāo)志位,以便后面的指令根據(jù)相應(yīng)的條件標(biāo)志來判斷是否執(zhí)行。

指令的語法格式:

CMP{<c>} <Rn>,<shifter_operand>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

<Rn>:第一個(gè)操作數(shù)。

<shifter_operand>:比較的數(shù)

指令舉例:

CMP 指令允許把一個(gè)寄存器的內(nèi)容與另一個(gè)寄存器的內(nèi)容或立即值進(jìn)行比較,更改狀態(tài)標(biāo)志來允許進(jìn)行條件執(zhí)行。它進(jìn)行一次減法,但不存儲結(jié)果,而是正確地更改標(biāo)志位。標(biāo)志位表示的是操作數(shù) 1 與操作數(shù) 2 比較的結(jié)果(其值可能為大于、小于、相等)。如果操作數(shù) 1 大于操作數(shù) 2,則此后的有 GT 后綴的

指令將可以執(zhí)行。

顯然,CMP 不需要顯式地指定 S 后綴來更改狀態(tài)標(biāo)志。

示例代碼 45-18 cmp 示例

1 cmp r1,#10 ;比較r1和立即數(shù)10是否相等

2 beq loop

通過上面的例子可以看出,CMP 指令與 SUBS 指令的區(qū)別在于 CMP 指令不保存運(yùn)算結(jié)果,在進(jìn)行兩個(gè)數(shù)據(jù)大小判斷時(shí),常用 CMP 指令及相應(yīng)的條件碼來進(jìn)行操作。

CMN 指令

CMN(Compare Negative)指令使用寄存器 Rn 的值減去 shifter_operand 的負(fù)數(shù)值,根據(jù)操作的結(jié)果更新 CPSR 中相應(yīng)的條件標(biāo)志位,以便后面的指令根據(jù)相應(yīng)的條件標(biāo)志來判斷是否執(zhí)行。

指令的語法格式:

CMN{<c>} <Rn>,<shifter_operand>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略<c>時(shí),指令為無條件執(zhí)行。

<Rn>:第一個(gè)操作數(shù)。

<shifter_operand>:比較的數(shù)

指令舉例:

CMN 指令將寄存器 Rn 中的值加上 shifter_operand 表示的數(shù)值,根據(jù)加法的結(jié)果設(shè)置 CPSR 中相應(yīng)的條件標(biāo)志位。寄存器 Rn 中的值加上 shifter_operand 的操作結(jié)果對 CPSR 中條件標(biāo)志位的影響,與寄存器Rn 中的值減去 shifter_operand 的操作結(jié)果的相反數(shù)對 CPSR 中條件標(biāo)志位的影響有細(xì)微差別。

下面的指令使 R0 值加 1,判斷 R0 是否為 1 的補(bǔ)碼,若是,則 Z 置位。

示例代碼 45-19 cmn 示例

1 cmn r0,#1

TST 測試指令

TST(Test)測試指令用于將一個(gè)寄存器的值和一個(gè)值進(jìn)行比較。條件標(biāo)志位根據(jù)兩個(gè)操作數(shù)做“邏輯與”后的結(jié)果設(shè)置。

TST{<c>} <Rn>,<shifter_operand>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

<Rn>:第一個(gè)操作數(shù)。

<shifter_operand>:比較的數(shù)

指令舉例:

下面的指令測試在 R0 中是否設(shè)置了位 0。

示例代碼 45-20 tst 示例

1 tst r7,#0x4 ;測試r7寄存器的值第2位是否置位

2 addeq r6,r7 ;如果置位執(zhí)行r6+r7

3 addne r8,r7 ;如果沒有置位執(zhí)行 r8+r7

TST 指令類似于 CMP 指令,不產(chǎn)生放置到目的寄存器中的結(jié)果。而是在給出的兩個(gè)操作數(shù)上進(jìn)行操作并把結(jié)果反映到狀態(tài)標(biāo)志上。使用 TST 指令來檢查是否設(shè)置了特定的位。操作數(shù) 1 是要測試的數(shù)據(jù)字而操作數(shù) 2 是一個(gè)位掩碼。經(jīng)過測試后,如果匹配則設(shè)置 Z 標(biāo)志,否則清除它。與 CMP 指令一樣,該指令不需要指定 S 后綴。

TEQ 指令

TEQ(Test Equivalence)指令用于將一個(gè)寄存器的值和一個(gè)算術(shù)值做比較。條件標(biāo)志位根據(jù)兩個(gè)操作數(shù)做“邏輯異或”后的結(jié)果設(shè)置。以便后面的指令根據(jù)相應(yīng)的條件標(biāo)志來判斷是否執(zhí)行。

指令的語法格式:

TEQ{<c>} <Rn>,<shifter_operand>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

<Rn>:第一個(gè)操作數(shù)。

<shifter_operand>:比較的數(shù)。

指令舉例:

示例代碼 45-21 teq 示例

1 teq r0, r1 ;r0與r1是否相等

2 addeq r0, r0, #1 ;若 r0==r1, eq 為真,則 r1=r1+1

乘法指令

ARM 乘法指令完成兩個(gè)數(shù)據(jù)的乘法。兩個(gè) 32 位二進(jìn)制數(shù)相乘的結(jié)果是 64 位的積。在有些 ARM 的處理器版本中,將乘積的結(jié)果保存到兩個(gè)獨(dú)立的寄存器中。另外一些版本只將最低有效 32 位存放到一個(gè)寄存器中。無論是哪種版本的處理器,都有乘—累加的變型指令,將乘積連續(xù)累加得到總和。而且有符號數(shù)和無符號數(shù)都能使用。對于有符號數(shù)和無符號數(shù),結(jié)果的最低有效位是一樣的。因此,對于只保留 32 位結(jié)果的乘法指令,不需要區(qū)分有符號數(shù)和無符號數(shù)這兩種情況。

如表所示為各種形式乘法指令的功能。

說明:

1) “RdHi:RdLo”是由 RdHi(最高有效 32 位)和 RdLo(最低有效 32 位)連接形成的 64 位

數(shù),“[31:0]”只選取結(jié)果的最低有效 32 位。

2) 簡單的賦值由“:=”表示。

3) 累加(將右邊加到左邊)是由“+=”表示。

4) 各個(gè)乘法指令中的位 S(參考下文具體指令的語法格式)控制條件碼的設(shè)置會產(chǎn)生以下結(jié)果。

1) 對于產(chǎn)生 32 位結(jié)果的指令形式,將標(biāo)志位 N 設(shè)置為 Rd 的第 31 位的值;對于產(chǎn)生長結(jié)果的

指令形式,將其設(shè)置為 RdHi 的第 31 位的值。

2) 對于產(chǎn)生 32 位結(jié)果的指令形式,如果 Rd 等于零,則標(biāo)志位 Z 置位;對于產(chǎn)生長結(jié)果的指令形式,RdHi 和 RdLo 同時(shí)為零時(shí),標(biāo)志位 Z 置位。

3) 將標(biāo)志位 C 設(shè)置成無意義的值。

4) 標(biāo)志位 V 不變。

?MUL 指令

MUL(Multiply)32 位乘法指令將 Rm 和 Rs 中的值相乘,結(jié)果的最低 32 位保存到 Rd 中。

指令的語法格式:?

MUL{<c>}{S} <Rd>,<Rm>,<Rs>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rd>:目的寄存器。

<Rn>:第一個(gè)操作數(shù)。

<Rs>:要與 Rn 相乘的數(shù)

指令舉例:

示例代碼 45-22 mul 示例

1 mul r1, r2, r3 ;r1 = r2 × r3

2 muls r0, r3, r7 ;r0 = r3 × r7

MLA 指令

MLA(Multiply Accumulate)32 位乘—累加指令將 Rm 和 Rs 中的值相乘,再將乘積加上第 3 個(gè)操作數(shù),結(jié)果的最低 32 位保存到 Rd 中。

指令的語法格式:

MLA{<c>}{S} <Rd>,<Rm>,<Rs>,<Rn>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rd>:目的寄存器。

<Rm>:第一個(gè)乘數(shù)。

<Rs>:第二個(gè)乘數(shù)。

<Rn>:與 Rm 與 Rs 的積相加。

指令舉例:

下面的指令完成 R1 = R2×R3+R0 的操作。

示例代碼 45-23 mla 示例

1 mla r1, r2, r3, r0

UMULL 指令

UMULL(Unsigned Multiply Long)為 64 位無符號乘法指令。它將 Rm 和 Rs 中的值做無符號數(shù)相乘,結(jié)果的低 32 位保存到 RdLo 中,高 32 位保存到 RdHi 中。

指令的語法格式:

UMULL{<c>}{S} <RdLo>,<RdHi>,<Rm>,<Rs>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略<c>時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rm>:第一個(gè)乘數(shù)。

<Rs>:第二個(gè)乘數(shù)

< RdHi >:Rm 與 Rs 的積的高 32 位

< RdLo >:Rm 與 Rs 的積的低 32 位

指令舉例:

示例代碼 45-24 umull 示例

1 umull r0, r1, r5, r8 ; (R1,R0) = R5 × R8

UMLAL 指令

UMLAL(Unsigned Multiply Accumulate Long)為 64 位無符號長乘—累加指令。指令將 Rm 和 Rs 中的值做無符號數(shù)相乘,64 位乘積與 RdHi、RdLo 相加,結(jié)果的低 32 位保存到 RdLo 中,高 32 位保存到RdHi 中。

指令的語法格式:

UMALL{<c>}{S} <RdLo>,<RdHi>,<Rm>,<Rs>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略<c>時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rm>:第一個(gè)乘數(shù)。

<Rs>:第二個(gè)乘數(shù)

<RdHi>:與 Rm 與 Rs 的積的高 32 位相加

<RdLo>:與 Rm 與 Rs 的積的低 32 位相加

指令舉例:

示例代碼 45-25 umlal 示例

1 umlal r0, r1, r5,r8 ;(r1,r0) = r5 × r8+(r1,r0)

SMULL 指令

SMULL(Signed Multiply Long)為 64 位有符號長乘法指令。指令將 Rm 和 Rs 中的值做有符號數(shù)相乘,結(jié)果的低 32 位保存到 RdLo 中,高 32 位保存到 RdHi 中。

指令的語法格式:

SMULL{<c>}{S} <RdLo>,<RdHi>,<Rm>,<Rs>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略<c>時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rm>:第一個(gè)乘數(shù)。

<Rs>:第二個(gè)乘數(shù)

< RdHi >:Rm 與 Rs 的積的高 32 位

< RdLo >:Rm 與 Rs 的積的低 32 位

指令舉例:

示例代碼 45-26 smull 示例

1 smull r2, r3, r7,r6 ;(r3,r2) = r7 × r6

SMLAL 指令

SMLAL(Signed Multiply Accumulate Long)為 64 位有符號長乘—累加指令。指令將 Rm 和 Rs 中的值做有符號數(shù)相乘,64 位乘積與 RdHi、RdLo 相加,結(jié)果的低 32 位保存到 RdLo 中,高 32 位保存到 RdHi

中。

指令的語法格式:

SMLAL{<c>}{S} <RdLo>,<RdHi>,<Rm>,<Rs>

{<c>}:為指令執(zhí)行的條件碼。當(dāng)忽略<c>時(shí),指令為無條件執(zhí)行。

{S}:決定指令的操作是否影響 CPSR。

<Rm>:第一個(gè)乘數(shù)。

<Rs>:第二個(gè)乘數(shù)

<RdHi>:與 Rm 與 Rs 的積的高 32 位相加

<RdLo>:與 Rm 與 Rs 的積的低 32 位相加

指令舉例:

示例代碼 45-27 smlal 示例

1 smlal r2, r3, r7,r6 ;(r3,r2)=r7×r6+(r3,r2)

Load/Store 指令

Load/Store 內(nèi)存訪問指令在 ARM 寄存器和存儲器之間傳送數(shù)據(jù)。ARM 指令中有 3 種基本的數(shù)據(jù)傳送指令。

? 單寄存器 Load/Store 指令

這些指令在 ARM 寄存器和存儲器之間提供更靈活的單數(shù)據(jù)項(xiàng)傳送方式。數(shù)據(jù)項(xiàng)可以是字節(jié)、

16 位半字或 32 位字。

? 多寄存器 Load/Store 內(nèi)存訪問指令

這些指令的靈活性比單寄存器傳送指令差,但可以使大量的數(shù)據(jù)更有效地傳送。它們用于進(jìn)程的進(jìn)入和退出、保存和恢復(fù)工作寄存器及復(fù)制存儲器中的一塊數(shù)據(jù)。

? 單寄存器交換指令

這些指令允許寄存器和存儲器中的數(shù)值進(jìn)行交換,在一條指令中有效地完成 Load/Store 操作。它們在用戶級編程中很少用到。它的主要用途是在多處理器系統(tǒng)中實(shí)現(xiàn)信號量(Semaphores)的操作,以保證不會同時(shí)訪問公用的數(shù)據(jù)結(jié)構(gòu)。

1、 單寄存器的 Load/Store 指令

LDR 指令

LDR 指令用于從內(nèi)存中將一個(gè) 32 位的字讀取到目標(biāo)寄存器。

指令的語法格式:

LDR{<c>} <Rd>,<addr_mode>

指令舉例:

示例代碼 45-28 ldr 示例

1 ldr r1,[r0,#0x12] ;將r0+12地址處的數(shù)據(jù)讀出,保存到r1中(r0的值不變)

2 ldr r1,[r0] ;將r0地址處的數(shù)據(jù)讀出,保存到r1中(零偏移)

3 ldr r1,[r0,r2] ;將r0+r2地址的數(shù)據(jù)讀出,保存到r1中(r0的值不變)

4 ldr r1,[r0,r2,lsl #2] ;將r0+r2×4地址處的數(shù)據(jù)讀出,保存到r1中(r0、r2的值不變)

5 ldr pc,[pc, #0x18] ;將程序跳轉(zhuǎn)到pc+0x18位置處

6 ldr rd,label ;label為程序標(biāo)號,label必須是當(dāng)前指令的-4~4kb范圍內(nèi)

7 ldr rd,[rn],#0x04 ;rn 的值用做傳輸數(shù)據(jù)的存儲地址。在數(shù)據(jù)傳送后,將偏移量 0x04 與 rn

相加,結(jié)果寫回到 rn 中。rn 不允許是 r15

STR 指令

STR 指令用于將一個(gè) 32 位的字?jǐn)?shù)據(jù)寫入到指令中指定的內(nèi)存單元。

指令的語法格式:

STR{<c>} <Rd>,<addr_mode>

指令舉例:

示例代碼 45-29 str 數(shù)據(jù)回寫

1 ldr r0, =0xE0200000

2 ldr r1, =0x00002222

3 str r1, [r0, #0x20]

LDRB 指令

LDRB 指令根據(jù) addr_mode 所確定的地址模式將 1 個(gè)字節(jié)(8bit)讀取到指令中的目標(biāo)寄存器 Rd。

指令的語法格式:

LDRB{<c>} <Rd>, <addr_mode>

STRB 指令

STRB 指令從寄存器中取出指定的 1 個(gè)字節(jié)(8bit)放入寄存器的低 8 位,并將寄存器的高位補(bǔ)0。

指令的語法格式:

STRB{<c>} <Rd>,<addr_mode>

) LDRH 指令

LDRH 指令用于從內(nèi)存中將一個(gè) 16 位的半字讀取到目標(biāo)寄存器。

如果指令的內(nèi)存地址不是半字節(jié)對齊的,指令的執(zhí)行結(jié)果不可預(yù)知。

指令的語法格式:

LDRH{<c>} <Rd>,<addr_mode>

STRH 指令

STRH 指令從寄存器中取出指定的 16 位半字放入寄存器的低 16 位,并將寄存器的高位補(bǔ)0。

指令的語法格式:

STRH{<c>} <Rd>,<addr_mode>

多寄存器的 Load/Store 內(nèi)存訪問指令

多寄存器的 Load/Store 內(nèi)存訪問指令也叫批量加載/存儲指令,它可以實(shí)現(xiàn)在一組寄存器和一塊連續(xù)的內(nèi)存單元之間傳送數(shù)據(jù)。LDM 用于加載多個(gè)寄存器,STM 用于存儲多個(gè)寄存器。多寄存器的 Load/Store內(nèi)存訪問指令允許一條指令傳送 16 個(gè)寄存器的任何子集或所有寄存器。多寄存器的 Load/Store 內(nèi)存訪問指令主要用于現(xiàn)場保護(hù)、數(shù)據(jù)復(fù)制和參數(shù)傳遞等。如表所示列出了多寄存器的 Load/Store 內(nèi)存訪問指令。

表 45.3.3.2 多寄存器操作指令

LDM 指令

LDM 指令將數(shù)據(jù)從連續(xù)的內(nèi)存單元中讀取到指令中指定的寄存器列表中的各寄存器中。當(dāng) PC 包含在LDM 指令的寄存器列表中時(shí),指令從內(nèi)存中讀取的字?jǐn)?shù)據(jù)將被作為目標(biāo)地址值,指令執(zhí)行后程序?qū)哪繕?biāo)地址處開始執(zhí)行,從而實(shí)現(xiàn)了指令的跳轉(zhuǎn)。

指令的語法格式:

LDM{<c>}<addressing_mode> <Rn>{!}, <registers>

STM 指令

STM 指令將指令中寄存器列表中的各寄存器數(shù)值寫入到連續(xù)的內(nèi)存單元中。主要用于塊數(shù)據(jù)的寫入、數(shù)據(jù)棧操作及進(jìn)入子程序時(shí)保存相關(guān)寄存器的操作。

指令的語法格式:

STM{<c>}<addressing_mode> <Rn>{!}, <registers>

批量數(shù)據(jù)傳送指令舉例

LDM/STM 批量加載/存儲指令可以實(shí)現(xiàn)在一組寄存器和一塊連續(xù)的內(nèi)存單元之間傳輸數(shù)據(jù)。LDM 為加載多個(gè)寄存器,STM 為存儲多個(gè)寄存器。允許一條指令傳送 16 個(gè)寄存器的任何子集或所有寄存器。指令格式如下:

?LDM{c}<模式> Rn{!},regist{?}

STM{c}<模式> Rn{!},regist{?}

LDM/STM 的主要用途有現(xiàn)場保護(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;后綴“!”表示最后的地址寫回到 Rn 中;寄存器列表 reglist 可包含多于一個(gè)寄存器或寄存器范圍,使用“,”分開,如{R1,R2,R6~R9},寄存器排列由小到大排列;“?”后綴不允許在用戶模式下使用,只能在系統(tǒng)模式下使用。若在LDM 指令用寄存器列表中包含有 PC 時(shí)使用,那么除了正常的多寄存器傳送外,將 SPSR 復(fù)制到 CPSR 中,這可用于異常處理返回;使用“?”后綴進(jìn)行數(shù)據(jù)傳送且寄存器列表不包含 PC 時(shí),加載/存儲的是用戶模式寄存器,而不是當(dāng)前模式寄存器。

示例代碼 45-30 批量數(shù)據(jù)傳送指令

1 LDMIA R0!,{R3~R9} ;加載R0指向的地址上的多字?jǐn)?shù)據(jù),保存到R3~R9中,R0值更新

2 STMIA R1!,{R3~R9} ;將R3~R9的數(shù)據(jù)存儲到R1指向的地址上,R1值更新

3 STMFD SP!,{R0~R7,LR} ;現(xiàn)場保存,將R0~R7、LR入棧

4 LDMFD SP!,{R0~R7,PC}? ;恢復(fù)現(xiàn)場,異常處理返回

在進(jìn)行數(shù)據(jù)復(fù)制時(shí),先設(shè)置好源數(shù)據(jù)指針,然后使用塊復(fù)制尋址指令 LDMIA/STMIA、LDMIB/STMIB、LDMDA/STMDA、LDMDB/STMDB 進(jìn)行讀取和存儲。而進(jìn)行堆棧操作時(shí),則要先設(shè)置堆棧指針,一般使用 SP 然后使用堆棧尋址指令 STMFD/LDMFD、STMED/LDMED、STMEA/LDMEA 實(shí)現(xiàn)堆棧操作。數(shù)據(jù)是存儲在基址寄存器的地址之上還是之下,地址是存儲第一個(gè)值之前還是之后、增加還是減少,如表所示。

使用 LDM/STM 進(jìn)行數(shù)據(jù)復(fù)制。

示例代碼 45-31 數(shù)據(jù)復(fù)制

1 LDR R0,=SrcData ;設(shè)置源數(shù)據(jù)地址

2 LDR R1,=DstData ;設(shè)置目標(biāo)地址

3 LDMIA R0,{R2~R9} ;加載8字?jǐn)?shù)據(jù)到寄存器R2~R9

4 STMIA R1,{R2~R9} ;存儲寄存器 R2~R9 到目標(biāo)地址

使用 LDM/STM 進(jìn)行現(xiàn)場寄存器保護(hù),常在子程序或異常處理使用。

示例代碼 45-32 保護(hù)現(xiàn)場

1 SENDBYTE:

2 STMFD SP!,{R0~R7,LR} ;寄存器壓棧保護(hù)

3 ...

4 BL DELAY ;調(diào)用DELAY子程序

5 ...

6 LDMFD SP!,{R0~R7,PC} ;恢復(fù)寄存器,并返回

單數(shù)據(jù)交換指令

交換指令是 Load/Store 指令的一種特例,它把一個(gè)寄存器單元的內(nèi)容與寄存器內(nèi)容交換。交換指令是一個(gè)原子操作(Atomic Operation),也就是說,在連續(xù)的總線操作中讀/寫一個(gè)存儲單元,在操作期間阻止其他任何指令對該存儲單元的讀/寫。交換指令如表所示。

SWP 字交換指令

SWP 指令用于將內(nèi)存中的一個(gè)字單元和一個(gè)指定寄存器的值相交換。操作過程如下:假設(shè)內(nèi)存單元地址存放在寄存器<Rn>中,指令將<Rn>中的數(shù)據(jù)讀取到目的寄存器 Rd 中,同時(shí)將另一個(gè)寄存器<Rm>的內(nèi)容寫入到該內(nèi)存單元中。

當(dāng)<Rd>和<Rm>為同一個(gè)寄存器時(shí),指令交換該寄存器和內(nèi)存單元的內(nèi)容。

指令的語法格式:

SWP{<c>} <Rd>,<Rm>,[<Rn>]

字節(jié)單元和一個(gè)指定寄存器的低 8 位值相交換,操作過程如下:假設(shè)內(nèi)存單元地址存放在寄存器<Rn>中,指令將<Rn>中的數(shù)據(jù)讀取到目的寄存器 Rd 中,寄存器 Rd 的高 24 位設(shè)為 0,同時(shí)將另一個(gè)寄存器<Rm>的低 8 位內(nèi)容寫入到該內(nèi)存字節(jié)單元中。當(dāng)<Rd>和<Rm>為同一個(gè)寄存器時(shí),指令交換該寄存器低 8 位內(nèi)容和內(nèi)存字節(jié)單元的內(nèi)容。

指令的語法格式:

SWP{<c>}B <Rd>,<Rm>,[<Rn>]

指令舉例:

示例代碼 45-33 swp 指令舉例

1 SWP R1,R1,[R0] ;將R1的內(nèi)容與R0指向的存儲單元內(nèi)容進(jìn)行交換

2 SWPB R1,R2,[R0] ;將 R0 指向的存儲單元內(nèi)容讀取一字節(jié)數(shù)據(jù)到 R1 中(高 24 位清零), 并將 R2 的內(nèi)容 寫入到該內(nèi)存單元中(最低字節(jié)有效),使用 SWP 指令可以方便地進(jìn)行信號量操作。

跳轉(zhuǎn)指令

跳轉(zhuǎn)(B)和跳轉(zhuǎn)連接(BL)指令是改變指令執(zhí)行順序的標(biāo)準(zhǔn)方式。ARM 一般按照字地址順序執(zhí)行指令,需要時(shí)使用條件執(zhí)行跳過某段指令。只要程序必須偏離順序執(zhí)行,就要使用控制流指令來修改程序計(jì)數(shù)器。盡管在特定情況下還有其他幾種方式實(shí)現(xiàn)這個(gè)目的,但轉(zhuǎn)移和轉(zhuǎn)移連接指令是標(biāo)準(zhǔn)的方式。跳轉(zhuǎn)指令改變程序的執(zhí)行流程或者調(diào)用子程序。這種指令使得一個(gè)程序可以使用子程序、if-then-else 結(jié)構(gòu)及循環(huán)。執(zhí)行流程的改變迫使程序計(jì)數(shù)器(PC)指向一個(gè)新的地址。

另一種實(shí)現(xiàn)指令跳轉(zhuǎn)的方式是通過直接向 PC 寄存器中寫入目標(biāo)地址值,實(shí)現(xiàn)在 4GB 地址空間中任意跳轉(zhuǎn),這種跳轉(zhuǎn)指令又稱為長跳轉(zhuǎn)。如果在長跳轉(zhuǎn)指令之前使用“MOV LR”或“MOV PC”等指令,可以保存將來返回的地址值,也就實(shí)現(xiàn)了在 4GB 的地址空間中的子程序調(diào)用。

1、 跳轉(zhuǎn)指令 B 及帶連接的跳轉(zhuǎn)指令 BL

跳轉(zhuǎn)指令 B 使程序跳轉(zhuǎn)到指定的地址執(zhí)行程序。帶連接的跳轉(zhuǎn)指令 BL 將下一條指令的地址復(fù)制到R14(即返回地址連接寄存器 LR)寄存器中,然后跳轉(zhuǎn)到指定地址運(yùn)行程序。需要注意的是,這兩條指令和目標(biāo)地址處的指令都要屬于 ARM 指令集。兩條指令都可以根據(jù) CPSR 中的條件標(biāo)志位的值決定指令是否執(zhí)行。

指令的語法格式:

B{L}{<c>} <target_address>

BL 指令用于實(shí)現(xiàn)子程序調(diào)用。子程序的返回可以通過將 LR 寄存器的值復(fù)制到 PC 寄存器來實(shí)現(xiàn)。下面 3 種指令可以實(shí)現(xiàn)子程序返回。

1) BX R14(如果體系結(jié)構(gòu)支持 BX 指令)。

2) MOV PC,R14。

3) 當(dāng)子程序在入口處使用了壓棧指令:

STMFD R13!,{<registers>,R14}

可以使用指令:

LDMFD R13!,{<registers>,PC}?

將子程序返回地址放入 PC 中。

ARM 匯編器通過以下步驟計(jì)算指令編碼中的 signed_immed_24。

1) 將 PC 寄存器的值作為本跳轉(zhuǎn)指令的基地址值。

2) 從跳轉(zhuǎn)的目標(biāo)地址中減去上面所說的跳轉(zhuǎn)的基地址,生成字節(jié)偏移量。由于 ARM 指令是字對齊的,該字節(jié)偏移量為 4 的倍數(shù)。

3) 當(dāng)上面生成的字節(jié)偏移量超過?33 554 432~+33 554 430 時(shí),不同的匯編器使用不同的代碼產(chǎn)生策略。否則,將指令編碼字中的 signed_immed_24 設(shè)置成上述字節(jié)偏移量的 bits[25:2]。

程序舉例:

程序跳轉(zhuǎn)到 LABLE 標(biāo)號處。

示例代碼 45-34 跳轉(zhuǎn)到標(biāo)號處

1 b lable

2 add r1,r2,#4

3 add r3,r2,#8

4 sub r3,r3,r1

5 lable:

6 sub r1,r2,#8

跳轉(zhuǎn)到絕對地址

示例代碼 45-35 跳轉(zhuǎn)到絕對地址?

1 b 0x1234

跳轉(zhuǎn)到子程序 func 處執(zhí)行,同時(shí)將當(dāng)前 PC 值保存到 LR 中。

示例代碼 45-36 子程序跳轉(zhuǎn)?

1 bl func

通過跳轉(zhuǎn)指令建立一個(gè)無限循環(huán)。

示例代碼 45-37 無限循環(huán)?

1 loop:

2 add r1,r2,#4

3 add r3,r2,#8

4 sub r3,r3,r1

5 b loop

通過使用跳轉(zhuǎn)使程序體循環(huán) 10 次。

示例代碼 45-38 有限循環(huán)?

1 mov r0,#10

2 loop:

3 subs r0,#1

4 bne loop

條件子程序調(diào)用示例。

示例代碼 45-39 條件調(diào)用?

1 cmp r0,#5 ;如果r0<5

2 bllt sub1 ;則調(diào)用

3 blge sub2 ;否則調(diào)用 sub2

帶狀態(tài)切換的跳轉(zhuǎn)指令 BX

帶狀態(tài)切換的跳轉(zhuǎn)指令(BX)使程序跳轉(zhuǎn)到指令中指定的參數(shù) Rm 指定的地址執(zhí)行程序,Rm 的第 0位復(fù)制到 CPSR 中 T 位,bit[31∶1]移入 PC。若 Rm 的 bit[0]為 1,則跳轉(zhuǎn)時(shí)自動將 CPSR 中的標(biāo)志位 T 置位,即把目標(biāo)地址的代碼解釋為 Thumb 代碼;若 Rm 的位 bit[0]為 0,則跳轉(zhuǎn)時(shí)自動將 CPSR 中的標(biāo)志位T 復(fù)位,即把目標(biāo)地址代碼解釋為 ARM 代碼。

指令的語法格式:

BX{<c>} <Rm>

當(dāng) Rm[1∶0]=0b10 時(shí),指令的執(zhí)行結(jié)果不可預(yù)知。因?yàn)樵?ARM 狀態(tài)下,指令是 4 字節(jié)對齊的。PC 可以作為 Rm 寄存器使用,但這種用法不推薦使用。當(dāng) PC 作為<Rm>使用時(shí),指令“BX PC”將程序跳轉(zhuǎn)到當(dāng)前指令下面第二條指令處執(zhí)行。雖然這樣跳轉(zhuǎn)可以實(shí)現(xiàn),但最好使用下面的指令完成這種跳轉(zhuǎn)。

MOV PC, PC或ADD PC, PC, #0

指令舉例:

轉(zhuǎn)移到 R0 中的地址,如果 R0[0]=1,則進(jìn)入 Thumb 狀態(tài)。

示例代碼 45-40 bx 指令示例?

1 bx r0

帶連接和狀態(tài)切換的連接跳轉(zhuǎn)指令 BLX 帶連接和狀態(tài)切換的跳轉(zhuǎn)指令(Branch with Link Exchange,BLX)使用標(biāo)號,用于使程序跳轉(zhuǎn)到 Thumb狀態(tài)或從 Thumb 狀態(tài)返回。該指令為無條件執(zhí)行指令,并用分支寄存器的最低位來更新 CPSR 中的 T 位,將返回地址寫入到連接寄存器 LR 中。

語法格式:

BLX <target_add>

其中,<target_add>為指令的跳轉(zhuǎn)目標(biāo)地址。該地址根據(jù)以下規(guī)則計(jì)算。

1) 將指令中指定的 24 位偏移量進(jìn)行符號擴(kuò)展,形成 32 位立即數(shù)。

2) 將結(jié)果左移兩位。

3) 位 H(bit[24])加到結(jié)果地址的第一位(bit[1])。

4) 將結(jié)果累加進(jìn)程序計(jì)數(shù)器(PC)中。

計(jì)算偏移量的工作一般由 ARM 匯編器來完成。這種形式的跳轉(zhuǎn)指令只能實(shí)現(xiàn)?32~32MB 空間的跳轉(zhuǎn)。左移兩位形成字偏移量,然后將其累加進(jìn)程序計(jì)數(shù)器(PC)中。這時(shí),程序計(jì)數(shù)器的內(nèi)容為 BX 指令地址加 8 字節(jié)。位 H(bit[24])也加到結(jié)果地址的第一位(bit[1]),使目標(biāo)地址成為半字地址,以執(zhí)行接下來的 Thumb 指令。計(jì)算偏移量的工作一般由 ARM 匯編器來完成。這種形式的跳轉(zhuǎn)指令只能實(shí)現(xiàn)?32~32MB 空間的跳轉(zhuǎn)。

指令舉例:

從 Thumb 狀態(tài)返回到 ARM 狀態(tài),使用 BX 指令。

示例代碼 45-41 Thumb 狀態(tài)返回 ARM 狀態(tài)

1 blx func

狀態(tài)操作指令

ARM 指令集提供了兩條指令,可直接控制程序狀態(tài)寄存器(Program State Register,PSR)。MRS 指令用于把CPSR或SPSR的值傳送到一個(gè)寄存器;MSR與之相反,把一個(gè)寄存器的內(nèi)容傳送到CPSR或SPSR。

這兩條指令相結(jié)合,可用于對 CPSR 和 SPSR 進(jìn)行讀/寫操作。程序狀態(tài)寄存器指令如表所示。

表 45.3.5.1 狀態(tài)操作指令

在指令語法中可看到一個(gè)稱為 fields 的項(xiàng),它可以是控制(C)、擴(kuò)展(X)、狀態(tài)(S)及標(biāo)志(F)的組合。

1、 MRS

MRS 指令用于將程序狀態(tài)寄存器的內(nèi)容傳送到通用寄存器中。

在 ARM 處理器中,只有 MRS 指令可以將狀態(tài)寄存器 CPSR 或 SPSR 讀出到通用寄存器中。

指令的語法格式:

MRS{c} Rd, PSR

其中,Rd 為目標(biāo)寄存器,Rd 不允許為程序計(jì)數(shù)器(PC)。PSR 為 CPSR 或 SPSR。

指令舉例:

示例代碼 45-42 讀取 CPSR 與 SPSR?

1 mrs r1,cpsr ;將cpsr狀態(tài)寄存器讀取,保存到r1中

2 mrs r2,spsr ;將 spsr 狀態(tài)寄存器讀取,保存到 r1 中

MRS 指令讀取 CPSR,可用來判斷 ALU 的狀態(tài)標(biāo)志及 IRQ/FIQ 中斷是否允許等;在異常處理程序中,讀 SPSR 可指定進(jìn)入異常前的處理器狀態(tài)等。MRS 與 MSR 配合使用,實(shí)現(xiàn) CPSR 或 SPSR 寄存器的讀—修改—寫操作,可用來進(jìn)行處理器模式切換,允許/禁止 IRQ/FIQ 中斷等設(shè)置。另外,進(jìn)程切換或允許異常中斷嵌套時(shí),也需要使用 MRS 指令讀取 SPSR 狀態(tài)值并保存起來。?

MSR

在 ARM 處理器中,只有 MSR 指令可以直接設(shè)置狀態(tài)寄存器 CPSR 或 SPSR。

指令的語法格式:

MSR{c} PSR_fields, #immed_8r

MSR{c} PSR_fields, Rm

其中,PSR 是指 CPSR 或 SPSR。<fields>設(shè)置狀態(tài)寄存器中需要操作的位。狀態(tài)寄存器的 32 位可以分為 4 個(gè) 8 位的域(field)。bits[31:24]為條件標(biāo)志位域,用 f 表示;bits[23:16]為狀態(tài)位域,用 s 表示;bits[15:8]為擴(kuò)展位域,用 x 表示;bits[7:0]為控制位域,用 c 表示;immed_8r 為要傳送到狀態(tài)寄存器指定域的立即數(shù),8 位;Rm 為要傳送到狀態(tài)寄存器指定域的數(shù)據(jù)源寄存器。

指令舉例:

示例代碼 45-43 MSR 指令示例

1 msr cpsr,#0xd3 ;cpsr[7:0]=0xd3,切換到管理模式

2 msr cpsr,r3 ;cpsr=r3

注意:只有在特權(quán)模式下才能修改狀態(tài)寄存器。

程序中不能通過 MSR 指令直接修改 CPSR 中的 T 位控制位來實(shí)現(xiàn) ARM 狀態(tài)/Thumb 狀態(tài)的切換,必須使用 BX 指令來完成處理器狀態(tài)的切換(因?yàn)?BX 指令屬轉(zhuǎn)移指令,它會打斷流水線狀態(tài),實(shí)現(xiàn)處理器狀態(tài)的切換)。MRS 與 MSR 配合使用,實(shí)現(xiàn) CPSR 或 SPSR 寄存器的讀—修改—寫操作,可用來進(jìn)行處理器模式切換及允許/禁止 IRQ/FIQ 中斷等設(shè)置。

程序狀態(tài)寄存器指令的應(yīng)用

使能 IRQ 中斷。

示例代碼 45-44 使能 IRQ 中斷

1 enable_irq:

2 mrs r0,cpsr

3 bic r0,r0,#0x80

4 msr cpsr_c,r0

5 mov pc,lr

禁止 IRQ 中斷。

示例代碼 45-45 禁止 IRQ 中斷

1 disable_irq:

2 mrs r0,cpsr

3 orr r0,r0,#0x80

4 msr cpsr,r0

5 mov pc,lr

?

設(shè)置中斷模式堆棧:

示例代碼 45-46 irq 模式堆棧

1 msr cpsr,#0xd2

2 ldr sp,stacksvc

協(xié)處理器指令

ARM 體系結(jié)構(gòu)允許通過增加協(xié)處理器來擴(kuò)展指令集。最常用的協(xié)處理器是用于控制片上功能的系統(tǒng)協(xié)處理器。例如,控制 Cache 和存儲管理單元的 cp15 寄存器。此外,還有用于浮點(diǎn)運(yùn)算的浮點(diǎn) 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 個(gè)協(xié)處理器,在程序執(zhí)行過程中,每個(gè)協(xié)處理器忽略 ARM 和其他協(xié)處理器指令。當(dāng)一個(gè)協(xié)處理器硬件不能執(zhí)行屬于它的協(xié)處理器指令時(shí),將產(chǎn)生一個(gè)未定義指令異常中斷,在該異常中斷處理過程中,可以通過軟件仿真該硬件操作。如果一個(gè)系統(tǒng)中不包含向量浮點(diǎn)運(yùn)算器,則可以選擇浮點(diǎn)運(yùn)算軟件包來支持向量浮點(diǎn)運(yùn)算。

ARM 協(xié)處理器可以部分地執(zhí)行一條指令,然后產(chǎn)生中斷。如除法運(yùn)算除數(shù)為 0 和溢出,這樣可以更好地處理運(yùn)行時(shí)產(chǎn)生(run-time-generated)的異常。但是,指令的部分執(zhí)行是由協(xié)處理器完成的,此過程對ARM 來說是透明的。當(dāng) ARM 處理器重新獲得執(zhí)行時(shí),它將從產(chǎn)生異常的指令處開始執(zhí)行。對某一個(gè)協(xié)處理器來說,并不一定用到協(xié)處理器指令中的所有的域。具體協(xié)處理器如何定義和操作完全由協(xié)處理器的制造商自己決定,因此,ARM 協(xié)處理器指令中的協(xié)處理器寄存器的標(biāo)識符及操作助記符也有各種不同的實(shí)現(xiàn)定義。程序員可以通過宏定義這些指令的語法格式。

ARM 協(xié)處理器指令可分為以下 3 類。

? 協(xié)處理器數(shù)據(jù)操作。協(xié)處理器數(shù)據(jù)操作完全是協(xié)處理器內(nèi)部操作,它完成協(xié)處理器寄存器的狀態(tài)改變。如浮點(diǎn)加運(yùn)算,在浮點(diǎn)協(xié)處理器中兩個(gè)寄存器相加,結(jié)果放在第 3 個(gè)寄存器中。這類指令包括 CDP 指令。

? 協(xié)處理器數(shù)據(jù)傳送指令。這類指令從寄存器讀取數(shù)據(jù)裝入?yún)f(xié)處理器寄存器,或?qū)f(xié)處理器寄存器的數(shù)據(jù)裝入存儲器。因?yàn)閰f(xié)處理器可以支持自己的數(shù)據(jù)類型,所以每個(gè)寄存器傳送的字?jǐn)?shù)與協(xié)處理器有關(guān)。ARM 處理器產(chǎn)生存儲器地址,但傳送的字節(jié)由協(xié)處理器控制。這類指令包括LDC 指令和 STC 指令。

? 協(xié)處理器寄存器傳送指令。在某些情況下,需要 ARM 處理器和協(xié)處理器之間傳送數(shù)據(jù)。如一個(gè)浮點(diǎn)運(yùn)算協(xié)處理器,F(xiàn)IX 指令從協(xié)處理器寄存器取得浮點(diǎn)數(shù)據(jù),將它轉(zhuǎn)換為整數(shù),并將整數(shù)傳送到 ARM 寄存器中。經(jīng)常需要用浮點(diǎn)比較產(chǎn)生的結(jié)果來影響控制流,因此,比較結(jié)果必須傳送到 ARM 的 CPSR 中。這類協(xié)處理器寄存器傳送指令包括 MCR 和 MRC。

如表所示列出了所有協(xié)處理器處理指令。

表 45.3.6.1 協(xié)處理器操作指令

下面簡單介紹一下比較常用的 MCR 及 MRC 命令的用法

ARM 寄存器到協(xié)處理器寄存器的數(shù)據(jù)傳送指令 MCR

指令的語法格式

MCR<c> <coproc>, <opc1>, <Rt>, <CRn>, <CRm>{, <opc2>}

<c>:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

<coproc>:協(xié)處理器名稱,范圍 p0-p15;

<opc1>:協(xié)處理器操作碼,范圍 0-15;

<Rt>:源寄存器,將 Rt 寄存器寫入?yún)f(xié)處理器;

<CRn>:協(xié)處理器的目標(biāo)寄存器;

<CRm>:協(xié)處理器中附加的目標(biāo)寄存器或者源操作寄存器,如果不需要附加信息就設(shè)置為 C0,否則

結(jié)果不可預(yù)測;

<opc2>:可選的協(xié)處理器特定操作碼,當(dāng)不需要時(shí)置 0。

協(xié)處理器寄存器到 ARM 寄存器的數(shù)據(jù)傳送指令 MRC

指令的語法格式

MRC<c> <coproc>, <opc1>, <Rt>, <CRn>, <CRm>{, <opc2>}

<c>:為指令執(zhí)行的條件碼。當(dāng)忽略< c >時(shí),指令為無條件執(zhí)行。

<coproc>:協(xié)處理器名稱,范圍 p0-p15;

<opc1>:協(xié)處理器操作碼,范圍 0-15;

<Rt>:源寄存器,將協(xié)處理器的內(nèi)容讀取到 Rt 寄存器;

<CRn>:協(xié)處理器的目標(biāo)寄存器;

<CRm>:協(xié)處理器中附加的目標(biāo)寄存器或者源操作寄存器,如果不需要附加信息就設(shè)置為 C0,否則

結(jié)果不可預(yù)測;

<opc2>:可選的協(xié)處理器特定操作碼,當(dāng)不需要時(shí)置 0。

指令舉例

示例代碼 45-47 使能 ICache

1 /******Cache Test*******/

2 mrc p15,0,r1,c1,c0,0

3 orr r1, r1, #(1 << 2) // Set C bit 整體使能Cache

4 orr r1, r1, #(1 << 12) //Set I bit 使能ICache

5 mcr p15,0,r1,c1,c0,0

6 /******End Test******/

異常產(chǎn)生指令

ARM 指令集中提供了兩條產(chǎn)生異常的指令,通過這兩條指令可以用軟件的方法實(shí)現(xiàn)異常。如表所示為 ARM 異常產(chǎn)生指令。

軟件中斷指令(Software Interrupt,SWI)用于產(chǎn)生軟中斷,從而實(shí)現(xiàn)從用戶模式變換到管理模式,CPSR 保存到管理模式的 SPSR 中,執(zhí)行轉(zhuǎn)移到 SWI 向量,在其他模式下也可以使用 SWI 指令,處理器同樣切換到管理模式。

指令的語法格式。

SWI{<c>} <immed_24>

指令舉例

示例代碼 45-48 swi 指令示例

1 swi 0 ;產(chǎn)生軟中斷,中斷號為0

2 swi 0x123456 ;產(chǎn)生軟中斷,中斷立即數(shù)為 0x123456

使用 SWI 指令時(shí),通常使用以下兩種方法進(jìn)行參數(shù)傳遞。

下面的程序產(chǎn)生一個(gè)中斷號為 12 的軟中斷。

示例代碼 45-49 swi 指令示例

1 mov r0,#34 ;設(shè)置功能號為34

2 swi 12 ;產(chǎn)生軟中斷,中斷號為 12

下面的例子通過 R0 傳遞中斷號,R1 傳遞中斷的子功能號。

示例代碼 45-50 swi 指令示例

1 mov r0,#12 ;設(shè)置12號軟中斷

2 mov r1,#34 ;設(shè)置功能號為34

3 swi 0

ARM 匯編實(shí)驗(yàn)

實(shí)驗(yàn)?zāi)康?/strong>

了解程序的運(yùn)行過程

掌握 ARM 匯編語言的基本使用;

熟悉 eclipse 開發(fā)工具建立匯編工程和仿真;

實(shí)驗(yàn)原理

根據(jù)上面闡述 RAM 匯編語言的使用語法和功能,編寫匯編程序,實(shí)現(xiàn)一個(gè)簡單的數(shù)據(jù)運(yùn)算操作。

? 可執(zhí)行程序的組成部分

在 linux 下一個(gè)可執(zhí)行的 elf 應(yīng)用程序,通常包含以下幾部分內(nèi)容。

圖 45-3 可執(zhí)行程序的組成部分

這里涉及到了代碼段、數(shù)據(jù)段、未初始化數(shù)據(jù)、堆、棧,幾個(gè)部分:

代碼段:代碼段在內(nèi)存中被映射為只讀。通常是用來存放程序執(zhí)行的指令。

數(shù)據(jù)段:通常用來存放程序中已初始化的(非 0)全局變量和靜態(tài)局部變量,數(shù)據(jù)段的起始位置由鏈接定位文件確認(rèn),大小在編譯鏈接時(shí)自動分配。

未初始化數(shù)據(jù):通常用來存放程序中未初始化和初始化為 0 的全局變量的一塊內(nèi)存區(qū)域,在程序載入時(shí)清零。

堆:保存函數(shù)內(nèi)部動態(tài)分配(malloc 或 new)的內(nèi)存。

棧:保存函數(shù)的局部變量(不包括 static 修飾的變量),參數(shù)以及返回值。

在匯編語言中一個(gè)可執(zhí)行程序一般至少包含:代碼段+數(shù)據(jù)段+BSS 段。

? 位置有關(guān)和位置無關(guān):

位置無關(guān)碼就是和位置無關(guān),這種代碼放在什么位置都能正常運(yùn)行,所以地址是動態(tài)的不能固定的。而位置有關(guān)碼就是和某個(gè)具體位置有關(guān)的代碼,而這個(gè)具體位置就是我們的鏈接地址。

? 鏈接地址:

在程序編譯的時(shí)候,每個(gè)目標(biāo)文件都是由源代碼編譯得到,最終多個(gè)目標(biāo)文件鏈接生成一個(gè)最終的可執(zhí)行文件,而鏈接地址就是指示鏈接器,各個(gè)目標(biāo)文件的在可執(zhí)行程序中的位置。比如,一個(gè)可執(zhí)行程序 a.out 由 a.o、b.o、c.o 組成,那么最終的 a.out 中誰在前、誰在中間、誰在結(jié)尾,都可以通過制定鏈接地址來決定。

? 運(yùn)行地址:

程序?qū)嶋H在內(nèi)存中運(yùn)行時(shí)候的地址,比如 CPU 要執(zhí)行一條指令,那么必然要通過給 PC 賦值,從對應(yīng)的地址空間中去取出來,那么這個(gè)地址就是實(shí)際的運(yùn)行地址。

? 加載地址和存儲地址:

每一個(gè)程序一開始都是存放在 flash 中的,而運(yùn)行是在內(nèi)存中,這個(gè)時(shí)候就需要從 flash 中將指令讀取到內(nèi)存中(運(yùn)行地址),flash 的地址就是加載地址。

圖 45-4 鏈接地址和運(yùn)行地址對比圖

實(shí)驗(yàn)內(nèi)容

創(chuàng)建鏈接腳本

示例代碼 45-51 鏈接腳本

1 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")

2 OUTPUT_ARCH(arm)

3 ENTRY(_start)

4 SECTIONS

5 {

6 . = 0xc2000040;

7 . = ALIGN(4);

8 .text :

9 {

10 start.o(.text)

11 *(.text)

12 }

13 . = ALIGN(4);

14 .rodata :

15 { *(.rodata) }

16 . = ALIGN(4);

17 .data :

18 { *(.data) }

19 . = ALIGN(4);

20 .bss :

21 { *(.bss) }

22 }

創(chuàng)建 Makefile 編譯腳本

示例代碼 45-52 Makefile 文件

1 SHELL=C:\Windows\System32\cmd.exe

2

3 CROSS_COMPILE = arm-none-eabi4 NAME = h_project

5

6 CPPFLAGS := -nostdlib -nostdinc -g

7 CFLAGS := -Wall -O2 -fno-builtin -g

8

9 LD = $(CROSS_COMPILE)ld

10 CC = $(CROSS_COMPILE)gcc

11 OBJCOPY = $(CROSS_COMPILE)objcopy

12 OBJDUMP = $(CROSS_COMPILE)objdump

13

14 export CC LD OBJCOPY OBJDUMP AR CPPFLAGS CFLAGS

15

16 objs := start.o

17 all: $(objs)

18 $(LD) -T map.lds -o $(NAME).elf $^

19 $(OBJCOPY) -O binary $(NAME).elf $(NAME).bin

20 $(OBJDUMP) -D $(NAME).elf > $(NAME).dis

21

22 %.o : %.S

23 $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c

24

25 %.o : %.c

26 $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c

27

28 clean:

29 rm *.o *.elf *.bin

匯編程序設(shè)計(jì)如下

示例代碼 45-53 匯編示例

1 .text

2 .global _start

3 _start:

4

5 mov r0, #0x9

6 nop

7 mov r1, #0x7

8

9 bl add_sub

10

11 stop:

12 b stop

13

14 add_sub:

15 add r2, r0, r1 ; r2=0x9+0x7=0x10

16 sub r3, r0, r1 ; r3=0x9-0x7=0x2

17

18 mul r4, r0,r1 ; r4=0x9*0x7=0x3f

19 mov pc, lr

實(shí)驗(yàn)步驟

1、 導(dǎo)入工程源碼

請參考導(dǎo)入一個(gè)已有工程章節(jié)的導(dǎo)入一個(gè)已有工程。

光盤實(shí)驗(yàn)源碼路徑:【資料光盤\華清遠(yuǎn)見-FS-MP1A 開發(fā)資料-2020-11-06\02-程序源碼\03-ARM 體系

結(jié)構(gòu)與接口技術(shù)\Cortex-A7\h_project】

2、 打開“Register”顯示框

單擊 window -> show view -> Register,

3、 單步仿真

配置完成之后,點(diǎn)擊“ ”開始仿真,彈出 Debug 框。

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

實(shí)驗(yàn)現(xiàn)象

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

單步運(yùn)行可以看到 R2、R3 和 R4 的值變化。

基于stm32mp157 linux開發(fā)板ARM裸機(jī)開發(fā)教程5:ARM微處理器指令系統(tǒng)(連載中)的評論 (共 條)

分享到微博請遵守國家法律
和顺县| 绥德县| 翼城县| 邹城市| 汪清县| 翁源县| 德江县| 本溪| 柏乡县| 巫溪县| 莫力| 内丘县| 株洲市| 宁乡县| 普定县| 镇江市| 罗甸县| 同心县| 项城市| 兖州市| 牟定县| 响水县| 特克斯县| 汕尾市| 新营市| 荣昌县| 深水埗区| 汝城县| 巧家县| 越西县| 荃湾区| 孙吴县| 鄂托克前旗| 巫山县| 镇宁| 和平区| 红河县| 石泉县| 额敏县| 黄浦区| 高邑县|