常用 ARM 指令集及匯編


ARM7TDMI(-S)指令集及匯編

ARM 處理器是基於精簡指令集計算機(RISC)原理設計的,指令集和相關譯碼機制 較為簡單,ARM7TDMI(-S)具有 32 位 ARM 指令集和 16 位 Thumb 指令集,ARM 指令集效率 高,但是代碼密度低,而 Thumb 指令集具有更好的代碼密度,卻仍然保持 ARM 的大多數 性能上的優勢,它是 ARM 指令集的子集。所有 ARM 指令都是可以有條件執行的,而 Thumb 指令僅有一條指令具備條件執行功能。ARM 程序和 Thumb 程序可相互調用,相互之間的 狀態切換開銷幾乎為零。

ARM 處理器尋址方式

尋址方式是根據指令中給出的地址碼字段來實現尋找真實操作數地址的方式,ARM 處理器有 9 種基本尋址方式。

寄存器尋址

操作數的值在寄存器中,指令中的地址碼字段指出的是寄存器編號,指令執行時直 接取出寄存器值操作。

寄存器尋址指令舉例如下:

MOV

R1,R2

;R2 -> R1

SUB

R0,R1,R2

;R1 - R2 -> R0

立即尋址

立即尋址指令中的操作碼字段后面的地址碼部分就是操作數本身,也就是說,數據就包含在指令當中,取出指令也就取出了可以立即使用的操作數(立即數)。

立即尋址指令舉例如下:

SUBS R0,R0,#1 ;R0 – 1 -> R0

MOV R0,#0xff00 ;0xff00 -> R0 立即數要以“#”為前綴,表示 16 進制數值時以“0x”表示。

寄存器偏移尋址

寄存器偏移尋址是ARM指令集特有的尋址方式,當第2操作數是寄存器偏移方式時, 第 2 個寄存器操作數在與第 1 個操作數結合之前,選擇進行移位操作。

寄存器偏移尋址方式指令舉例如下:

MOV R0,R2,LSL #3 ;R2 的值左移 3 位,結果放入 R0,即 R0 = R2 * 8

ANDS R1,R1,R2,LSL R3 ;R2 的值左移 R3 位,然后和 R1 相與操作,結果放入 R1 可采用的移位操作如下:

LSL:邏輯左移(Logical Shift Left),寄存器中字的低端空出的位補 0

LSR:邏輯右移(Logical Shift Right),寄存器中字的高端空出的位補 0

ASR:算術右移(Arithmetic Shift Right),移位過程中保持符號位不變,即如 果源操作數為正數,則字的高端空出的位補 0,否則補 1

ROR:循環右移(Rotate Right),由字的低端移出的位填入字的高端空出的位 RRX:帶擴展的循環右移(Rotate Right eXtended by 1place),操作數右移一位,

高端空出的位用原 C 標志值填充。

各移位操作如下圖所示。

clip_image001clip_image0020 LSL 移位操作

clip_image003clip_image0040 LSR 移位操作

ASR 移位操作

clip_image005clip_image006ROR 移位操作

clip_image007clip_image008clip_image002[1]C RRX 移位操作

寄存器間接尋址

寄存器間接尋址指令中的地址碼給出的是一個通用寄存器編號,所需要的操作數保 存在寄存器指定地址的存儲單元中,即寄存器為操作數的地址指針。

寄存器間接尋址指令舉例如下:

LDR R1,[R2] ;將 R2 中的數值作為地址,取出此地址中的數據保存在 R1 中 SWP R1,R1,[R2];將如中的數值作為地址,取出此地址中的數值與 R1 中的值交換

基址尋址

基址尋址是將基址寄存器的內容與指令中給出的偏移量相加,形成操作數的有效地

址,基址尋址用於訪問基址附近的存儲單元,常用於查表,數組操作,功能部件寄存器

訪問等。 基址尋址指令舉例如下:

LDR R2,[R3,#0x0F] ;將 R3 中的數值加 0x0F 作為地址,取出此地址的數值保存在 R2 中

STR R1,[R0,#-2] ;將 R0 中的數值減 2 作為地址,把 R1 中的內容保存到此地址位置

多寄存器尋址

多寄存器尋址就是一次可以傳送幾個寄存器值,允許一條指令傳送 16 個寄存器的 任何子集或所有寄存器。

多寄存器尋址指令舉例如下:

LDMIA R1!,{R2-R7,R12} ;將 R1 單元中的數據讀出到 R2-R7,R12,R1 自動加 1

STMIA R0!,{R3-R6,R10};將 R3-R6,R10 中的數據保存到 R0 指向的地址,R0 自動加 1

使用多寄存器尋址指令時,寄存器子集的順序時由小到大的順序排列,連續的寄存 器可用“-”連接,否則,用“,”分隔書寫。

堆棧尋址

堆棧是特定順序進行存取的存儲區,操作順序分為“后進先出”和“先進后出”, 堆棧尋址時隱含的,它使用一個專門的寄存器(堆棧指針)指向一塊存儲區域(堆棧), 指針所指向的存儲單元就是堆棧的棧頂。存儲器堆棧可分為兩種:

向上生長:向高地址方向生長,稱為遞增堆棧 向下生長:向低地址方向生長,稱為遞減堆棧 堆棧指針指向最后壓入的堆棧的有效數據項,稱為滿堆棧;堆棧指針指向下一個要

放入的空位置,稱為空堆棧。這樣就有 4 中類型的堆棧表示遞增和遞減的滿堆棧和空堆棧的各種組合。

滿遞增:堆棧通過增大存儲器的地址向上增長,堆棧指針指向內含有效數據項的 最高地址。指令如 LDMFA,STMFA 等。

空遞增:堆棧通過增大存儲器的地址向上增長,堆棧指針指向堆棧上的第一個空 位置。指令如 LDMEA,STMEA 等。

滿遞減:堆棧通過減小存儲器的地址向下增長,堆棧指針指向內含有效數據項的最

低地址。指令如 LDMFD,STMFD 等。 空遞減:堆棧通過減小存儲器的地址向下增長,堆棧指針指向堆棧下的第一個空

位置。指令如 LDMED,STMED 等。 堆棧尋址指令舉例如下:

STMFD SP!,{R1-R7,LR} ; 將 R1~R7,LR 入棧。滿遞減堆棧。

LDMFD SP!,{R1-R7,LR} ;數據出棧,放入 R1~R7,LR 寄存器。滿遞減堆棧。

塊拷貝尋址

多寄存器傳送指令用於一塊數據從存儲器的某一位置拷貝到另一位置。 塊拷貝尋址指令舉例如下:

STMIA

R0!,{R1-R7}

;將 R1~R7 的數據保存到存儲器中,存儲器指針在保存第一

;個值之后增加,增長方向為向上增長。

STMIB

R0!,{R1-R7}

;將 R1~R7 的數據保存到存儲器中,存儲器指針在保存第一

;個值之前增加,增長方向為向上增長。

STMDA

R0!,{R1-R7}

;將 R1~R7 的數據保存到存儲器中,存儲器指針在保存第一

;個值之后增加,增長方向為向下增長。

STMDB

R0!,{R1-R7}

;將 R1~R7 的數據保存到存儲器中,存儲器指針在保存第一

;個值之前增加,增長方向為向下增長。

相對尋址

相對尋址是基址尋址的一種變通,由程序計數器 PC 提供基准地址,指令中的地址碼字段作為偏移量,兩者相加后得到的地址即為操作數的有效地址。

相對尋址指令舉例如下:

BL ROUTE1 ;調用到 ROUTE1 子程序 BEQ LOOP ;條件跳轉到 LOOP 標號處

LOOP MOV R2,#2

ROUTE1

指令集介紹

ARM 指令集

指令格式

基本格式

<opcode>{<cond>}{S} <Rd>,<Rn>{,<opcode2>} 其中,<>內的項是必須的,{}內的項是可選的,如<opcode>是指令助記符,是必須

的,而{<cond>}為指令執行條件,是可選的,如果不寫則使用默認條件 AL(無條件執行)。

opcode 指令助記符,如 LDR,STR 等

cond 執行條件,如 EQ,NE 等

S 是否影響 CPSR 寄存器的值,書寫時影響 CPSR,否則不影響 Rd 目標寄存器

Rn 第一個操作數的寄存器

operand2 第二個操作數

指令格式舉例如下:

LDR R0,[R1] ;讀取 R1 地址上的存儲器單元內容,執行條件 AL BEQ DATAEVEN ;跳轉指令,執行條件 EQ,即相等跳轉到 DATAEVEN ADDS R1,R1,#1 ;加法指令,R1+1=R1 影響 CPSR 寄存器,帶有 S

SUBNES R1,R1,#0xD;條件執行減法運算(NE),R1-0xD=>R1,影響 CPSR 寄存器,帶有 S

2 個操作數

在 ARM 指令中,靈活的使用第 2 個操作數能提高代碼效率,第 2 個操作數的形式如 下:

immed_8r

常數表達式,該常數必須對應 8 位位圖,即常數是由一個 8 位的常數循環移位偶數

位得到。

合法常量:

0x3FC、0、0xF0000000、200,0xF0000001 非法常量:

0x1FE、511、0xFFFF、0x1010、0xF0000010 常數表達式應用舉例如下:

MOV R0,#1 ;R0=1

AND R1,R2,#0x0F ;R2 與 0x0F,結果保存在 R1

LDR R0,[R1],#-4 ;讀取 R1 地址上的存儲器單元內容,且 R1=R1-4

Rm

寄存器方式,在寄存器方式下操作數即為寄存器的數值。 寄存器方式應用舉例:

SUB

R1,R1,R2

;R1-R2=>R1

MOV

PC,R0

;PC=R0,程序跳轉到指定地址

LDR

R0,[R1],-R2

;讀取 R1 地址上的存儲器單元內容並存入 R0,且 R1=R1-R2

Rm,shift

寄存器移位方式。將寄存器的移位結果作為操作數,但 RM 值保存不變,移位方法 如下:

ASR #n 算術右移 n 位(1≤n≤32) LSL #n 邏輯左移 n 位(1≤n≤31) LSR #n 邏輯左移 n 位(1≤n≤32) ROR #n 循環右移 n 位(1≤n≤31) RRX 帶擴展的循環右移 1 位

type Rs 其中,type 為 ASR,LSL,和 ROR 中的一種;Rs 偏移量寄存器,低 8 位有效,若其值大於或等於 32,則第 2 個操作數的結果為 0(ASR、ROR 例外)。

寄存器偏移方式應用舉例:

ADD R1,R1,R1,LSL #3 ;R1=R1*9

SUB R1,R1,R2,LSR#2 ;R1=R1-R2*4

R15 為處理器的程序計數器 PC,一般不要對其進行操作,而且有些指令是不允許使 用 R15,如 UMULL 指令。

條件碼

使用指令條件碼,可實現高效的邏輯操作,提高代碼效率。 條件碼表

條件碼助記符

標志

含義

EQ

Z=1

相等

NE

Z=0

不相等

CS/HS

C=1

無符號數大於或等於

CC/LO

C=0

無符號數小於

MI

N=1

負數

PL

N=0

正數或零

VS

V=1

溢出

VC

V=0

沒有溢出

HI

C=1,Z=0

無符號數大於

LS

C=0,Z=1

無符號數小於或等於

GE

N=V

帶符號數大於或等於

LT

N!=V

帶符號數小於

GT

Z=0,N=V

帶符號數大於

LE

Z=1,N!=V

帶符號數小於或等於

AL

任何

無條件執行(指令默認條件)

對於 Thumb 指令集,只有 B 指令具有條件碼執行功能,此指令條件碼同表 2.1,但

如果為無條件執行時,條件碼助記符“AL”不能在指令中書寫。 條件碼應用舉例如下:

比較兩個值大小,並進行相應加 1 處理,C 代碼為

if(a>b)a++;

else b++;

對應的 ARM 指令如下。其 R0 為 a,R1 為 b。 CMP R0,R1 ;R0 與 R1 比較

ADDHI R0,R0,#1 ;若 R0>R1,則 R0=R0+1

ADDLS R1,R1,#1 ;若 R0<=R1,則 R1=R1+1 若兩個條件均成立,則將這兩個數值相加,C 代碼為

If((a!=10)&&(b!=20)) a=a+b;

對應的 ARM 指令如下.其中 R0 為 a,R1 為 b. CMP R0,#10 ;比較 R0 是否為 10

CMPNE R1,#20 ;若 R0 不為 10,則比較 R1 是否 20

ADDNE R0,R0,R1 ;若 R0 不為 10 且 R1 不為 20,指令執行,R0=R0+R1

ARM 存儲器訪問指令

ARM 處理是加載/存儲體系結構的典型的 RISC 處理器,對存儲器的訪問只能使用加 載和存儲指令實現。ARM 的加載/存儲指令是可以實現字、半字、,無符/有符字節操作; 批量加載/存儲指令可實現一條指令加載/存儲多個寄存器的內容,大大提高效率;SWP 指令是一條寄存器和存儲器內容交換的指令,可用於信號量操作等。ARM 處理器是馮. 諾依曼存儲結構,程序空間、RAM 空間及 IO 映射空間統一編址,除對對 RAM 操作以外, 對外圍 IO、程序數據的訪問均要通過加載/存儲指令進行。

ARM 存儲訪問指令表

助記符

說明

操作

條件碼位置

LDR Rd,addressing

加載字數據

Rd←[addressing],addressing 索引

LDR{cond}

LDRB Rd,addressing

加載無符字節數據

Rd←[addressing],addressing 索引

LDR{cond}B

LDRT Rd,addressing

以用戶模式加載字數據

Rd←[addressing],addressing 索引

LDR{cond}T

LDRBT Rd,addressing

以用戶模式加載無符號字數據

Rd←[addressing],addressing 索引

LDR{cond}BT

LDRH Rd,addressing

加載無符半字數據

Rd←[addressing],addressing 索引

LDR{cond}H

LDRSB Rd,addressing

加載有符字節數據

Rd←[addressing],addressing 索引

LDR{cond}SB

LDRSH Rd,addressing

加載有符半字數據

Rd←[addressing],addressing 索引

LDR{cond}SH

STR Rd,addressing

存儲字數據

[addressing]←Rd,addressing 索引

STR{cond}

STRB Rd,addressing

存儲字節數據

[addressing]←Rd,addressing 索引

STR{cond}B

STRT Rd,addressing

以用戶模式存儲字數據

[addressing]←Rd,addressing 索引

STR{cond}T

SRTBT Rd,addressing

以用戶模式存儲字節數據

[addressing]←Rd,addressing 索引

STR{cond}BT

STRH Rd,addressing

存儲半字數據

[addressing]←Rd,addressing 索引

STR{cond}H

LDM{mode} Rn{!},reglist

批量(寄存器)加載

reglist←[Rn…],Rn 回存等

LDM{cond}{more}

STM{mode} Rn{!},rtglist

批量(寄存器)存儲

[Rn…]← reglist,Rn 回存等

STM{cond}{more}

SWP Rd,Rm,Rn

寄存器和存儲器字數據交換

Rd←[Rd],[Rn]←[Rm](Rn≠Rd 或 Rm)

SWP{cond}

SWPB Rd,Rm,Rn

寄存器和存儲器字節數據交換

Rd←[Rd],[Rn]←[Rm](Rn≠Rd 或 Rm)

SWP{cond}B

X LDR STR

加載/存儲字和無符號字節指令.使用單一數據傳送指令(STR 和 LDR)來裝載和存儲 單一字節或字的數據從/到內存.LDR 指令用於從內存中讀取數據放入寄存器中;STR 指 令用於將寄存器中的數據保存到內存.指令格式如下:

LDR{cond}{T} Rd,<地址>;加載指定地址上的數據(字),放入 Rd 中 STR{cond}{T} Rd,<地址>;存儲數據(字)到指定地址的存儲單元,要存儲的數據在 Rd 中 LDR{cond}B{T} Rd,<地址>;加載字節數據,放入 Rd 中,即 Rd 最低字節有效,高 24 位清零

STR{cond}B{T} Rd,<地址>;存儲字節數據,要存儲的數據在 Rd,最低字節有效

其中,T 為可選后綴,若指令有 T,那么即使處理器是在特權模式下,存儲系統也將訪 問看成是處理器是在用戶模式下.T 在用戶模式下無效,不能與前索引偏移一起使用 T. LDR/STR 指令尋址是非常靈活的,由兩部分組成,一部分為一個基址寄存器,可以為任一 個通用寄存器,另一部分為一個地址偏移量.地址偏移量有以下 3 種格式:

(1) 立即數.立即數可以是一個無符號數值,這個數據可以加到基址寄存器,也可 以從基址寄存器中減去這個數值.指令舉例如下:

LDR R1,[R0,#0x12] ;將 R0+0x12 地址處的數據讀出,保存到 R1 中(R0 的值不變) LDR R1,[R0,#-0x12];將 R0-0x12 地址處的數據讀出,保存到 R1 中(R0 的值不變) LDR R1,[R0] ;將 R0 地址處的數據讀出,保存到 R1 中(零偏移) (2)寄存器.寄存器中的數值可以加到基址寄存器,也可以從基址寄存器中減去這

個數值.指令舉例值.指令舉例如下:

LDR R1,[R0,R2] ;將 R0+R2 地址的數據計讀出,保存到 R1 中(R0 的值不變) LDR R1,[R0,-R2] ;將 R0-R2 地址處的數據計讀出,保存到 R1 中(R0 的值不變) (3)寄存器及移位常數.寄存器移位后的值可以加到基址寄存器,也可以從基址寄

存器中減去這個數值.指令舉例如下:

LDR R1,[R0,R2,LSL #2] ;將 R0+R2*4 地址處的數據讀出,保存到 R1 中(R0,R2 的值不變) LDR R1,[R0,-R2,LSL #2];將 R0-R2*4 地址處的數據計讀出,保存到 R1 中(R0,R2 的值不變) 從尋址方式的地址計算方法分,加載/存儲指令有以下 4 種形式:

(1)零偏移.Rn 的值作為傳送數據的地址,即地址偏移量為 0.指令舉例如下: LDR Rd,[Rn]

(2)前索引偏移.在數據傳送之前,將偏移量加到 Rn 中,其結果作為傳送數據的存儲地址.若使用后綴“!”,則結果寫回到 Rn 中,且 Rn 值不允許為 R15.指令舉例如下:

LDR Rd,[Rn,#0x04]! LDR Rd,[Rn,#-0x04] (3)程序相對偏移.程序相對偏移是索引形式的另一個版本.匯編器由 PC 寄存器計

算偏移量,並將 PC 寄存器作為 Rn 生成前索引指令.不能使用后綴“!”.指令舉例如下: LDR Rd,label ;label 為程序標號,label 必須是在當前指令的±4KB 范圍內 (4) 后索引偏移.Rn 的值用做傳送數據的存儲地址.在數據傳送后,將偏移量與 Rn

相加,結果寫回到 Rn 中.Rn 不允許是 R15.指令舉例如下:

LDR Rd,[Rn],#0x04

地址對准--大多數情況下,必須保證用於 32 位傳送的地址是 32 位對准的. 加載/存儲字和無符號字節指令舉例如下:

LDR R2,[R5] ;加載 R5 指定地址上的數據(字),放入 R2 中

STR R1,[R0,#0x04] ;將 R1 的數據存儲到 R0+0x04 存儲單元,R0 值不變

LDRB R3,[R2],#1 ;讀取 R2 地址上的一字節數據,並保存到 R3 中,R2=R3+1

STRB R6,[R7] ;讀R6的數據保存到R7指定的地址中,只存儲一字節數據 加載/存儲半字和帶符號字節.這類 LDR/STR 指令可能加載帶符字節\加載帶符號半字、加載/存儲無符號半字.偏移量格式、尋址方式與加載/存儲字和無符號字節指令相

同.指令格式如下:

LDR{cond}SB Rd,<地址> ;加載指定地址上的數據(帶符號字節),放入 Rd 中 LDR{cond}SH Rd,<地址> ;加載指定地址上的數據(帶符號字節),放入 Rd 中 LDR{cond}H Rd,<地址> ;加載半字數據,放入 Rd 中,即 Rd 最低 16 位有效,高 16 位清零 STR{cond}H Rd,<地址> ;存儲半字數據,要存儲的數據在 Rd,最低 16 位有效 說明:帶符號位半字/字節加載是指帶符號位加載擴展到 32 位;無符號位半字加載

是指零擴展到 32 位.

地址對准--對半字傳送的地址必須為偶數.非半字對准的半字加載將使 Rd 內容不 可靠,非半字對准的半字存儲將使指定地址的 2 字節存儲內容不可靠.

加載/存儲半字和帶符號字節指令舉例如下:

LDRSB R1[R0,R3] ;將 R0+R3 地址上的字節數據讀出到 R1,高 24 位用符號位擴展 LDRSH R1,[R9] ;將 R9 地址上的半字數據讀出到 R1,高 16 位用符號位擴展 LDRH R6,[R2],#2 ;將 R2 地址上的半字數據讀出到 R6,高 16 位用零擴展,,R2=R2+1

SHRH R1,[R0,#2]!;將 R1 的數據保存到 R2+2 地址中,只存儲低 2 字節數據,R0=R0+2

LDR/STR 指令用於對內存變量的訪問,內存緩沖區數據的訪問、查表、外圍部件的 控制操作等等,若使用 LDR 指令加載數據到 PC 寄存器,則實現程序跳轉功能,這樣也就實現了程序散轉。

變量的訪問

NumCount EQU 0x40003000 ;定義變量 NumCount

GPIO 設置

LDR R0,=NumCount ;使用 LDR 偽指令裝載 NumCount 的地址到 R0

LDR R1,[R0] ;取出變量值

ADD R1,R1,#1 ;NumCount=NumCount+1

STR R1,[R0] ;保存變量值

GPIO-BASE EQU 0Xe0028000 ;定義 GPIO 寄存器的基地址

LDR R0,=GPIO-BASE

LDR R1,=0x00FFFF00 ;裝載 32 位立即數,即設置值

STR R1,[R0,#0x0C] ;IODIR=0x00FFFF00, IODIR 的地址為 0xE002800C

MOV R1,#0x00F00000

STR R1,[R0,#0x04] ;IOSET=0x00F00000,IOSET 的地址為 0xE0028004

程序散轉

MOV R2,R2,LSL #2 ;功能號乘上 4,以便查表

LDR PC,[PC,R2] ;查表取得對應功能子程序地址,並跳轉 NOP

FUN-TAB DCD FUN-SUB0

DCD FUN-SUB1

DCD FUN-SUB2

X LDM STM

批量加載/存儲指令可以實現在一組寄存器和一塊連續的內存單元之間傳輸數 據.LDM 為加載多個寄存器,STM 為存儲多個寄存器.允許一條指令傳送 16 個寄存器的任 何子集或所有寄存器.指令格式如下:

LDM{cond}<模式> Rn{!},reglist{^}

STM{cond}<模式> Rn{!},reglist{^}

LDM /STM 的主要用途是現場保護、數據復制、參數傳送等。其模式有 8 種,如下:(前 面 4 種用於數據塊的傳輸,后面 4 種是堆棧操作)

(1) IA:每次傳送后地址加 4 (2) IB:每次傳送前地址加 4 (3) DA:每次傳送后地址減 4 (4) DB:每次傳送前地址減 4 (5) FD:滿遞減堆棧

(6) ED:空遞增堆棧 (7) FA:滿遞增堆棧 (8) EA:空遞增堆棧

其中,寄存器Rn為基址寄存器,裝有傳送數據的初始地址,Rn不允許為R15;后綴“!” 表示最后的地址寫回到Rn中;寄存器列表reglist可包含多於一個寄存器或寄存器范圍, 使用“,”分開,如{R1,R2,R6-R9},寄存器排列由小到大排列;“^”后綴不允許在用戶 模式呈系統模式下使用,若在 LDM 指令用寄存器列表中包含有 PC 時使用,那么除了正 常的多寄存器傳送外,將 SPSR 拷貝到 CPSR 中,這可用於異常處理返回;使用“^”后 綴進行數據傳送且寄存器列表不包含 PC 時,加載/存儲的是用戶模式的寄存器,而不是 當前模式的寄存器。

地址對准――這些指令忽略地址的位[1:0] 批量加載/存儲指令舉例如下:

LDMIA R0!,{R3-R9} ;加載 R0 指向的地址上的多字數據,保存到 R3~R9 中,R0 值更新 STMIA R1!,{R3-R9} ;將 R3~R9 的數據存儲到 R1 指向的地址上,R1 值更新 STMFD SP!,{R0-R7,LR} ;現場保存,將 R0~R7、LR 入棧

LDMFD SP!,{R0-R7,PC}^;恢復現場,異常處理返回 在進行數據復制時,先設置好源數據指針,然后使用塊拷貝尋址指令 LDMIA/STMIA、

LDMIB/STMIB、LDMDA/STMDA、LDMDB/STMDB 進行讀取和存儲。而進行堆棧操作時,則要先設置堆棧指針,一般使用 SP 然后使用堆棧尋址指令 STMFD/LDMFD、STMED。LDMED、 STMFA/LDMFA、STMEA/LDMEA 實現堆棧操作。

多寄存器傳送指令示意圖如圖所示,其中 R1 為指令執行前的基址寄存器,R1 則為指

clip_image009clip_image010令執行完后的基址寄存器. R1’

R7

R6

clip_image011R1 R5 4008H

4004H

4000H

a)指令 STMIA R1!,{R5-R7}

clip_image012R1’

clip_image013R1

R7

R6

clip_image014R5 4008H

4004H

4000H

b)指令 STMIB R1!,{R5-R7}

R1

clip_image013[1]R1’

R7

clip_image015R6

clip_image016R5 4008H

4004H

4000H

c)指令 STMDA R1!, {R5-R7}

R1

clip_image013[2]R1’

clip_image017R7

clip_image018R6 4008H R5 4004H

4000H

d)指令 STMDB R1!,{R5-R7}

數據是存儲在基址寄存器的地址之上還是之下,地址是在存儲第一個值之前還是之后增加還是減少.

多寄存器傳送指令映射

向上生長

向下生長

滿

滿

增加

之前

STMIB

LDMIB

STMFA

LDMED

之后

STMIA

LDMIA

STMEA

LDMFD

增加

之前

LDMDB

STMDB

LDMEA

STMFD

之后

LDMDA

STMDA

LDMFA

STMED

使用 LDM/STM 進行數據復制:

LDR R0,=SrcData ;設置源數據地址 LDR R1,=DstData ;設置目標地址

LDMIA R0,{R2-R9} ;加載 8 字數據到寄存器 R2~R9

STMIA R1,{R2~R9} ;存儲寄存器 R2~R9 到目標地址 使用 LDM/STM 進行現場寄存器保護,常在子程序中或異常處理使用: SENDBYTE

STMFD SP!,{R0-R7,LR} ;寄存器入堆

BL DELAY ;調用 DELAY 子程序

LDMFD SP!,{R0-R7,PC} ;恢復寄存器,並返回

X SWP

寄存器和存儲器交換指令.SWP 指令用於將一個內存單元(該單元地址放在寄存器 Rn 中)的內容讀取到一個寄存器 Rd 中,同時將另一個寄存器 Rm 的內容寫入到該內存單 元中.使用 SWP 可實現信號量操作.

指令格式如下: SWP{cond}{B} Rd,Rm,[Rn]

其中,B 為可選后綴,若有 B,則交換字節,否則交換 32 位字:Rd 為數據從存儲器加載

到的寄存器;Rm 的數據用於存儲到存儲器中,若 Rm 與 Rn 相同,則為寄存器與存儲器內容 進行交換;Rn 為要進行數據交換的存儲器地址,Rn 不能與 Rd 和 Rm 相同.

SWP 指令舉例如下:

SWP R1,R1,[R0] ;將 R1 的內容與 R0 指向的存儲單元的內容進行交換

SWP R1,R2,,[R0] ;將R0指向的存儲單元內容讀取一字節數據到R1中(高

24 位清零),並將 R2 的內容寫入到該內存單元中(最低字節有效) 使用 SWP 指令可以方便地進行信號量的操作:

12C_SEM EQU 0x40003000

12C_SEM_WAIT

MOV R0,#0

LDR R0,=12C_SEM

SWP R1,R1,[R0] ;取出信號量,並設置其為 0

CMP R1,#0 ;判斷是否有信號

BEQ 12C_SEM_WAIT ;若沒有信號,則等待

ARM 數據處理指令

數據處理指令大致可分為 3 類;數據傳送指令(如 MOV、MVN),算術邏輯運算指令 (如 ADD,SUM,AND),比較指令(如 CMP,TST).數據處理指令只能對寄存器的內容進行操作. 所有 ARM 數據處理指令均可選擇使用 S 后綴,以影響狀態標志.比較指令 CMP,CMN,TST 和 TEQ 不需要后綴 S,它們會直接影響狀態標志.

ARM 數據處理指令

助記符號

說明

操作

條件碼位置

MOV Rd ,operand2

數據轉送

Rd←operand2

MOV {cond}{S}

MVN Rd ,operand2

數據非轉送

Rd←(operand2)

MVN {cond}{S}

ADD Rd,Rn operand2

加法運算指令

Rd←Rn+operand2

ADD {cond}{S}

SUB Rd,Rn operand2

減法運算指令

Rd←Rn-operand2

SUB {cond}{S}

RSB Rd,Rn operand2

逆向減法指令

Rd←operand2-Rn

RSB {cond}{S}

ADC Rd,Rn operand2

帶進位加法

Rd←Rn+operand2+carry

ADC {cond}{S}

SBC Rd,Rn operand2

帶進位減法指令

Rd←Rn-operand2-(NOT)Carry

SBC {cond}{S}

RSC Rd,Rn operand2

帶進位逆向減法指令

Rd←operand2-Rn-(NOT)Carry

RSC {cond}{S}

AND Rd,Rn operand2

邏輯與操作指令

Rd←Rn&operand2

AND {cond}{S}

ORR Rd,Rn operand2

邏輯或操作指令

Rd←Rn|operand2

ORR {cond}{S}

EOR Rd,Rn operand2

邏輯異或操作指令

Rd←Rn^operand2

EOR {cond}{S}

BIC Rd,Rn operand2

位清除指令

Rd←Rn&(~operand2)

BIC {cond}{S}

CMP Rn,operand2

比較指令

標志 N、Z、C、V←Rn-operand2

CMP {cond}

CMN Rn,operand2

負數比較指令

標志 N、Z、C、V←Rn+operand2

CMN {cond}

TST Rn,operand2

位測試指令

標志 N、Z、C、V←Rn&operand2

TST {cond}

TEQ Rn,operand2

相等測試指令

標志 N、Z、C、V←Rn^operand2

TEQ {cond}

數據傳送指令

X MOV

數據傳送指令.將 8 位圖立即數或寄存器(operant2)傳送到目標寄存器 Rd,可用於 移位運算等操作.指令格式如下:

MOV{cond}{S} Rd,operand2

MOV 指令舉例如下:

MOV

R1#0x10

;R1=0x10

MOV

R0,R1

;R0=R1

MOVS

R3,R1,LSL

#2

;R3=R1<<2,並影響標志位

MOV

PC,LR

;PC=LR ,子程序返回

X MVN

數據非傳送指令.將 8 位圖立即數或寄存器(operand2)按位取反后傳送到目標寄存 器(Rd),因為其具有取反功能,所以可以裝載范圍更廣的立即數.指令格式如下:

MVN{cond}{S} Rd,operand2

MVN 指令舉例如下:

MVN

R1,#0xFF

;R1=0xFFFFFF00

MVN

R1,R2

;將 R2 取反,結果存到 R1

算術邏輯運算指令

X ADD

加法運算指令.將 operand2 數據與 Rn 的值相加,結果保存到 Rd 寄存器.指令格式如

下:

ADD{cond}{S} Rd,Rn,operand2

ADD 指令舉例如下:

ADDS R1,R1,#1 ;R1=R1+1

ADD R1,R1,R2 ;R1=R1+R2

ADDS R3,R1,R2,LSL #2 ;R3=R1+R2<<2

X SUB

減法運算指令.用寄存器 Rn 減去 operand2.結果保存到 Rd 中.指令格式如下: SUB{cond}{S} Rd,Rn,operand2

SUB 指令舉例如下

SUBS R0,R0,#1 ;R0=R0-1

SUBS R2,R1,R2 ;R2=R1-R2

SUB R6,R7,#0x10 ;R6=R7-0x10

X RSB

逆向減法指令.用寄存器 operand2 減法 Rn,結果保存到 Rd 中.指令格式如下: RSB{cond}{S} Rd,Rn,operand2

SUB 指令舉例如下

RSB R3,R1,#0xFF00 ;R3=0xFF00-R1

RSBS R1,R2,R2,LSL #2 ;R1=R2<<2-R2=R2×3

RSB R0,R1,#0 ;R0=-R1

X ADC

帶進位加法指令.將 operand2 的數據與 Rn 的值相加,再加上 CPSR 中的 C 條件標志位.結果保存到 Rd 寄存器.指令格式如下;

ADC{cond}{S} Rd,Rn,operand2

ADC 指令舉例如下:

ADDS

R0,R0,R2

ADC

R1,R1,R3

;使用 ADC 實現 64 位加法,(R1、R0)=(R1、R0)+(R3、R2)

X SBC

帶進位減法指令。用寄存器 Rn 減去 operand2,再減去 CPSR 中的 C 條件標志位的非(即若 C 標志清零,則結果減去 1),結果保存到 Rd 中。指令格式如下:

SCB{cond}{S}Rd,Rn,operand2

SBC 指令舉例如下

SUBS

R0,R0,R2

SBC

R1,R1,R3

;使用 SBC 實現 64 位減法,(R1,R0)-(R3,R2)

X RSC

帶進位逆向減法指令.用寄存器 operand2 減去 Rn,再減去 CPSR 中的 C 條件標志位, 結果保存到 Rd 中.指令格式如下:

RSC{cond}{S} Rd,Rn,operand2

RSC 指令舉例如下:

RSBS

R2,R0,#0

RSC

R3,R1,#0

;使用 RSC 指令實現求 64 位數值的負數

X AND

邏輯與操作指令.將 operand2 值與寄存器 Rn 的值按位作邏輯與操作,結果保存到 Rd 中.指令格式如下:

AND{cond}{S} Rd,Rn,operand2

AND 指令舉例如下:

ANDS R0,R0,#x01 ;R0=R0&0x01,取出最低位數據 AND R2,R1,R3 ;R2=R1&R3

X ORR

邏輯或操作指令.將operand2的值與寄存器Rn的值按位作邏輯或操作,結果保存到 Rd 中.指令格式如下:

ORR{cond}{S} Rd,Rn,operand2

ORR 指令舉例如下:

ORR R0,R0,#x0F ;將 R0 的低 4 位置 1

MOV R1,R2,LSR #4

ORR R3,R1,R3,LSL #8 ;使用 ORR 指令將近 R2 的高 8 位數據移入到 R3低8位

X EOR

邏輯異或操作指令.將operand2 的值與寄存器Rn的值按位作邏輯異或操作,結果保 存到 Rd 中.指令格式如下:

EOR{cond}{S}Rd,Rn,operand2

EOR 指令舉例如下:

EOR R1,R1,#0x0F ;將 R1 的低 4 位取反

EOR R2,R1,R0 ;R2=R1^R0

EORS R0,R5,#0x01 ;將 R5 和 0x01 進行邏輯異或,結果保存到 R0,並影響標志位

X BIC

位清除指令.將寄存器Rn的值與operand2的值的反碼按位作邏輯與操作,結果保存 到 Rd 中.指令格式如下:

BIC{cond}{S}Rd,Rn,operand2

BIC 指令舉例如下:

BIC

R1,R1,#0x0F

;將 R1 的低 4 位清零,其它位不變

BIC

R1,R2,R3

;將拭的反碼和 R2 相邏輯與,結果保存到 R1

比較指令

X CMP

比較指令.指令使用寄存器 Rn 的值減去 operand2 的值,根據操作的結果理新 CPSR 中的相應條件標志位,以便后面的指令根據相應的條件標志來判斷是否執行.指令格式 如下:

CMP{cond} Rn,operand2

CMP 指令舉例如下:

CMP R1,#10 ;R1 與 10 比較,設置相關標志位 CMP R1,R2 ;R1 與 R2 比較,設置相關標志位

CMP 指令與 SUBS 指令的區別在於 CMP 指令不保存運算結果.在進行兩個數據大小判斷時,常用 CMP 指令及相應的條件碼來操作.

X CMN

負數比較指令.指令使用寄存器 Rn 與值加上 operand2 的值,根據操作的結果理新 CPSR 中的相應條件標志位,以便后面的指令根據相應的條件標志來判斷是否執行,指令 格式如下:

CMN{cond} Rn,operand2

CMN R0,#1 ;R0+1,判斷 R0 是否為 1 的補碼,若是 Z 置位

CMN 指令與 ADDS 指令的區別在於 CMN 指令不保存運算結果.CMN 指令可用於負數比

較,比如 CMNR0,#1 指令則表示 R0 與-1 比較,若 R0 為-(即 1 的補碼),則 Z 置位,否則 Z 復位.

X TST

位測試指令.指令將寄存器Rn的值與operand2的值按位作邏輯與操作,根據操作的結果理新 CPSR 中相應的條件標志位,以便后面指令根據相應的條件標志來判斷是否執行.指令格式如下:

TST{cond} Rn,operand2

TST 指令舉例如下:

TST R0,#0x01 ;判斷 R0 的最低位是否為 0

TST R1,#0x0F ;判斷 R1 的低 4 位是否為 0

TST 指令與 ANDS 指令的區別在於 TST4 指令不保存運算結果.TST 指令通常於 EQ,NE 條件碼配合使用,當所有測試位均為 0 時,EQ 有效,而只要有一個測試為不為 0,則 NE 有 效.

X TEQ

相等測試指令.指令寄存器Rn的值與operand2的值按位作邏輯異或操作,根據操作的結果理新 CPSR 中相應條件標志位,以便后面的指令根據相應的條件標志來判斷是否執行.指令格式如下:

TEQ{cond} Rn,operand2

TEQ 指令舉例如下:

TEQ R0,R1 ;比較 R0 與 R1 是否相等(不影響 V 位和 C 位)

TST 指令與 EORS 指令的區別在於 TST 指令不保存運算結果.使用 TEQ 進行相等測試, 常與 EQNE 條件碼配合使用,當兩個數據相等時,EQ 有效,否則 NE 有效.

乘法指令

ARM7TDMI(-S)具有 32×32 乘法指令,32×32 乘加指令,32×32 結果為 64 位的乘/ 乘法指令.

ARM 乘法指令

助記符

說明

操作

條件碼位置

MUL Rd,Rm,Rs

32 位乘法指令

Rd←Rm*Rs (Rd≠Rm)

MUL{cond}{S}

MLA Rd,Rm,Rs,Rn

32 位乘加指令

Rd←Rm*Rs+Rn (Rd≠Rm)

MLA{cond}{S}

UMULL RdLo,RdHi,Rm,Rs

64 位無符號乘法指令

(RdLo,RdHi)←Rm*Rs

UMULL{cond}{S}

UMLAL RdLo,RdHi,Rm,Rs

64 位無符號乘加指令

(RdLo,RdHi)←Rm*Rs+(RdLo,RdHi)

UMLAL{cond}{S}

SMULL RdLo,RdHi,Rm,Rs

64 位有符號乘法指令

(RdLo,RdHi)←Rm*Rs

SMULL{cond}{S}

SMLAL RdLo,RdHi,Rm,Rs

64 位有符號乘加指令

(RdLo,RdHi)←Rm*Rs+(RdLo,RdHi)

SMLAL{cond}{S}

X MUL

32 位乘法指令.指令將 Rm 和 Rs 中的值相乘,結果的低 32 位保存到 Rd 中.指令格式如下:

MUL{cond}{S} Rd,Rm,Rs

MUL 指令舉例如下:

MUL R1,R2,R3 ;R1=R2×R3

MULS R0,R3,R7 ;R0=R3×R7,同時設置 CPSR 中的 N 位和 Z 位

X MLA

32 位乘加指令.指令將 Rm 和 Rs 中的值相乘,再將乘積加上第 3 個操作數,結果的低

32 位保存到 Rd 中.指令格式如下: MLA{cond}{S} Rd,Rm,Rs,Rn MLA 指令舉例如下:

MLA R1,R2,R3,R0 ;R1=R2×R3+10

X UMULL

64 位無符號乘法指令.指令將 Rm 和 Rs 中的值作無符號數相乘,結果的低 32 位保存到 RsLo 中,而高 32 位保存到 RdHi 中,.指令格式如下:

UMULL{cond}{S} RdLo,RdHi,Rm,Rs

UMULL 指令舉例如下:

UMULL R0,R1,R5,R8 ;(R1、R0)=R5×R8

X UMLAL

64 位無符號乘加指令.指令將 Rm 和 Rs 中的值作無符號數相乘,64 位乘積與 RdHi,RdLo 相加,結果的低 32 位保存到 RdLo 中,而高 32 位保存到 RdHi 中.指令格式如 下:

UMLAL{cond}{S} RdLo,RdHi,Rm,Rs

UMLAL 指令舉例如下:

UMLAL R0,R1,R5,R8 ;(R1,R0)=R5×R8+(R1,R0)

X SMULL

64 位有符號乘法指令.指令將 Rm 和 Rs 中的值作有符號數相乘,結果的低 32 位保存到 RdLo 中,而高 32 位保存到 RdHi 中.指令格式如下:

SMULL{cond}{S} RdLo,RdHi,Rm,Rs

SMULL 指令舉例如下:

SMULL R2,R3,R7,R6 ;(R3,R2)=R7×R6

X SMLAL

64 位有符號乘加指令.指令將 Rm 和 Rs 中的值作有符號數相乘,64 位乘積與 RdHi,RdLo,相加,結果的低 32 位保存到 RdLo 中,而高 32 位保存到 RdHi 中.指令格式如下:

SMLAL{cond}{S} RdLo,RdHi,Rm,Rs

SMLAL 指令舉例如下:

SMLAL R2,R3,R7,R6 ;(R3,R2)=R7×R6+(R3,R2)

ARM 跳轉指令

在 ARM 中有兩種方式可以實現程序的跳轉,一種是使用跳轉指令直接跳轉,另一種 則是直接向 PC 寄存器賦值實現跳轉.跳轉指令有跳轉指令 B,帶鏈接的跳轉指令 BL 帶狀 態切換的跳轉指令 BX.

跳轉指令

助記符

說明

操作

條件碼位置

B label

跳轉指令

Pc←label

B{cond}

BL label

帶鏈接的跳轉指令

LR←PC-4, PC←label

BL{cond}

BX Rm

帶狀態切換的跳轉指令

PC←label,切換處理狀態

BX{cond}

X B

跳轉指令.跳轉到指定的地址執行程序.指令格式如下; B{cond} label

跳轉指令 B 舉例如下:

B WAITA ;跳轉到 WAITA 標號處

B 0x1234 ;跳轉到絕對地址 0x1234 處 跳轉到指令 B 限制在當前指令的±32Mb 的范圍內.

X BL

帶鏈接的跳轉指令.指令將下一條指令的地址拷貝到 R14(即 LR)鏈接寄存器中,然后跳轉到指定地址運行程序.指令格式如下:

BL{cond} label 帶鏈接的跳轉指令 BL 舉例如下: BL DELAY

跳轉指令 B 限制在當前指令的±32MB 的范圍內.BL 指令用於子程序調用

X BX

帶狀態切換的跳轉指令.跳轉到 Rm 指定的地址執行程序,若 Rm 的位[0]為 1,則跳轉

時自動將 CPSR 中的標志 T 置位,即把目標地址的代碼解釋為 Thumb 代碼;若 Rm 的位[0]

為 0,則跳轉時自動將 CPSR 中的標志 T 復位,即把目標地址的代碼解釋為 ARM 代碼.指令 格式如下:

BX{cond} Rm 帶狀態切換的跳轉指令 BX 舉例如下 ADRL R0,ThumbFun+1

BX R0 ;跳轉到R0指定的地址,並根據R0的最低位來切換處理器狀態

ARM 協處理器指令

ARM 支持協處理器操作,協處理器的控制要通過協處理器命令實現.

ARM 協處理器指令

助記符

說明

操作

條件碼位置

CDP

coproc,opcodel,CRd,CRn,CRm{,opcode2}

協處理器數據操作指令

取決於協處理器

CDP{cond}

LDC{L} coproc,CRd〈地址〉

協處理器數據讀取指令

取決於協處理器

LDC{cond}{L}

STC{L} coproc,CRd,〈地址〉

協處理器數據寫入指令

取決於協處理器

STC{cond}{L}

MCR coproc, opcodel,Rd,CRn,{,opcode2}

ARM 寄存器到協處理器寄存

器的數據傳送指令

取決於協處理器

MCR{cond}

MRC coproc, opcodel,Rd,CRn,{,opcode2}

協處理器寄存器到 ARM 寄存

器到數據傳送指令

取決於協處理器

MCR{cond}

X CDP

協處理器數據操作指令.ARM 處理器通過 CDP 指令通知 ARM 協處理器執行特定的操作.該操作由協處理器完成,即對命令的參數的解釋與協處理器有關,指令的使用取決於 協處理器.若協處理器不能成功地執行該操作,將產生未定義指令異常中斷.指令格式如 下:

CDP{cond} coproc,opcodel,CRd,CRn,CRm{,opcode2}

其中: coproc 指令操作的協處理器名.標准名為 pn,n 為 0~15. opcodel 協處理器的特定操作碼

CRd 作為目標寄存器的協處理器寄存器. CRN 存放第 1 個操作數的協處理器寄存器.

CRm 存放第 2 個操作數的協處理器寄存器.

Opcode2 可選的協處理器特定操作碼.

CDP

指令舉例如下:

CDP

p7,0,c0,c2,c3,0

;協處理器 7 操作,操作碼為 0,可選操作碼為 0

CDP

X LDC

p6,1,c3,c4,c5

;協處理器操作,操作碼為 1

協處理器數據讀取指令.LDC 指令從某一連續的內存單元將數據讀取到協處理器的

寄存器中.協處理器數據的數據的傳送,由協處理器來控傳送的字數.若協處理器不能成 功地執行該操作,將產生未定義指令異常中斷.指令格式如下;

LDC{cond}{L} coproc,CRd,<地址>

其中: L 可選后綴,指明是長整數傳送.

coproc 指令操作的協處理器名.標准名為 pn,n 為 0~15

CRd 作為目標寄存的協處理器寄存器.

<地址> 指定的內存地址 LDC 指令舉例如下:

LDC p5,c2,[R2,#4];讀取 R2+4 指向的內存單元的數據,傳送到協處理器 p5 的 c2 寄存器中

LDC p6,c2,[R1] ;讀取是指向的內存單元的數據,傳送到協處理器 p6 的 c2 寄存器中

X STC

協處理器數據寫入指令.STC 指令將協處理器的寄存器數據寫入到某一連續的內存 單元中.進行協處理器數據的數據傳送,由協處理器來控制傳送的字數.若協處理器不能 成功地執行該操作,將產生未定義指令異常中斷.指令格式如下;

STC{cond}{L} coproc,CRd,<地址> 其中:

L 可選后綴,指明是長整數傳送.

coproc 指令操作的協處理器名.標准名為 pn,n 為 0~15

CRd 作為目標寄存的協處理器寄存器.

<地址> 指定的內存地址

STC 指令舉例如下: STC p5,c1,[R0]

STC p5,c1,[Ro,#-0x04]

X MCR

ARM寄存器到協處理器寄存器的數據傳送指令.MCR指令將ARM處理器的寄存器中的 數據傳送到協處理器的寄存器中.若協處理器不能成功地執行該操作,將產生未定義指 令異常中斷.指令格式如下;

MCR{cond} coproc,opcodel,Rd,CRn,CRm{,opcode2}

其中 coproc 指令操作的協處理器名.標准名為 pn,n 為 0~15. cpcodel 協處理器的特定操作碼.

CRD 作為目標寄存器的協處理器寄存器. CRn 存放第 1 個操作數的協處理器寄存器 CRm 存放第 2 個操作數的協處理器寄存器. Opcode2 可選的協處理器特定操作碼.

MCR 指令舉例如下:

MCR p6,2,R7,c1,c2, MCR P7,0,R1,c3,c2,1,

X MRC

協處理器寄存器到 ARM 寄存器到的數據傳送指令.MRC 指令將協處理器寄存器中的 數據傳送到 ARM 處理器的寄存器中.若協處理器不能成功地執行該操作.將產生未定義 異常中斷.指令格式如下.

MRC {cond} coproc,opcodel,Rd,CRn,CRm{,opcode2}

其中 coproc 指令操作的協處理器名.標准名為 pn,n,為 0~15 opcodel 協處理器的特定操作碼.

CRd 作為目標寄存器的協處理器寄存器.

CRn 存放第 1 個操作數的協處理器寄存器.

CRm 存放第 2 個操作數的協處理器寄存器. opcode2 可選的協處理器特定操作碼.

MRC 指令舉例如下 MRC p5,2,R2,c3,c2

MRC p7,0,R0,c1,c2,1

ARM 雜項指令

助記符

說明

操作

條件碼位置

SWI immed_24

軟中斷指令

產生軟中斷,處理器進入管理模式

SWI{cond}

MRS Rd,psr

讀狀態寄存器指令

Rd←psr,psr 為 CPSR 或 SPSR

MRS{cond}

MSR psr_fields,Rd/#immed_8r

寫狀態寄存器指令

psr_fields←Rd/#immed_8r,psr 為 CPSR 或 SPSR

MSR{cond}

X SWI

軟中斷指令.SWI 指令用於產生軟中斷,從而實現在用戶模式變換到管理模式,CPSR 保存到管理模式的 SPSR 中,執行轉移到 SWI 向量,在其它模式下也可使用 SWI 指令,處理 同樣地切換到管理模式.指令格式如下;

SWI{cond} immed_24

其中 immed_24 24 位立即數,值為 0~16777215 之間的整數 SWI 指令舉例如下:

SWI 0 ;軟中斷,中斷立即數為 0

SWI 0x123456 ;軟中斷,中斷立即數為 0x123456

使用 SWI 指令時,通常使用以下兩種方法進行傳遞參數,SWI 異常中斷處理程序就可 以提供相關的服務,這兩種方法均是用戶軟件協定.SWI 異常中斷處理程序要通過讀取 引起軟中斷的 SWI 指令,以取得 24 位立即數.

1.指令 24 位的立即數指定了用戶請求的服務類型,參數通過用寄存器傳遞 MOV R0,#34 ;設置了功能號為 34

SWI 12 ;調用 12 號軟中斷

2.指令中的24位立即數被忽略,用戶請求的服務類型由寄存器R0的值決定,參數通

過其它的通用寄存器傳遞.

MOV R0,#12 ;調用 12 號軟中斷 MOV R1,#34 ;設置子功能號為 34

SWI 0

在 SWI 異常中斷處理程序中,取出 SWI 立即數的步驟為:首先確定引起軟中斷的 SWI 指令是 ARM 指令還時 Thumb 指令,這可通過對 SPSR 訪問得到:然后要取得該 SWI 指令的 地址,這可通過訪問 LR 寄存器得到:接着讀出指令,分解出立即數.

讀出 SWI 立即數

T_bit EQU 0x20

SWI_Hander

STMFD SP!,{R0_R3,R12,LR} ;現場保護 MRS R0,SPSR ;讀取 SPSR STMFD SP!,{R0} ;保存 SPSR

TST R0,#T_bit ;測試 T 標志位

LDRNEH R0,[LR,#-2] ;若是 Thumb 指令,讀取指令碼(16 位) BICNE R0,R0,#0xFF00 ;取得 Thumb 指令的 8 位立即數

LDREQ R0,[LR,#-4] ;若是 ARM 指令,讀取指令碼(32 位) BICNQ R0,R0,#0xFF00000 ;取得 ARM 指令的 24 位立即數

LDMFD SP!,{R0-R3,R12,PC}^ ;SWI 異常中斷返回

X MRS

讀狀態寄存器指令.在 ARM 處理器中,只有 MRS 指令可以狀態寄存器 CPSR 或 SPSR 讀出到通用寄存器中.指令格式如下;

MRS{cond} Rd ,psr

其中; Rd 目標寄存器.Rd 不允許為 R15. psr CPSR 或 SPSR

SWI 指令舉例如下

MRS R1,CPSR ;將 CPSR 狀態寄存器讀取,保存到 R1 中

MRS R2,SPSR ;將 SPSR 狀態寄存器讀取,保存到 R2 中

MRS 指令讀取 CPSR,可用來判斷 ALU 的狀態標志,或 IRQ,FIQ 中斷是否允許等;在異 常處理程序中,讀 SPSR 可知道進行異常前的處理器狀態等.MRS 與 MSR 配合使用,實現 CPSR 或 SPSR 寄存器的讀—修改---寫操作,可用來進行處理器模式切換(),允許?禁止 IRQ/FIQ 中斷等設置.另外,進程切換或允許異常中斷嵌套時,也需要使用 MRS 指令讀取 SPSR 狀態值.保存起來.

使能 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

X MSR

寫狀態寄存器指令.在 ARM 處理器中.只有 MSR 指令可以直接設置狀態寄存器 CPSR 或 SPSR.指令格式如下

MSR{cond} psr_fields,#immed_8r

MSR{cond} psr_fields,Rm

其中: psr CPSR 或 SPSR

fields 指定傳送的區域.Fields 可以是以下的一種或多種(字母必須為小寫):

c 控制域屏蔽字節(psr[7…0])

x 擴展域屏蔽字節(psr[15…8])

s 狀態域屏蔽字節(psr[23.…16])

f 標志域屏蔽字節(psr[31…24])

immed_8r 要傳送到狀態寄存器指定域的立即數,8 位.

Rm 要傳送到狀態寄存器指定域的數據的源寄存器. MSR 指令舉例如下

MSR CPSR_c,#0xD3 ;CPSR[7…0]=0xD3,即切換到管理模式. MSR CPSR_cxsf,R3 ;CPSR=R3 只有在特權模式下才能修改狀態寄存器.

程序中不能通過 MSR 指令直接修改 CPSR 中的 T 控制位來實現 ARM 狀態/Thumb 狀態 的切換,必須使用 BX 指令完成處理器狀態的切換(因為 BX 指令屬轉移指令,它會打斷流 水線狀態,實現處理器狀態切換).MRS 與 MSR 配合使用,實現 CPSR 或 SPSR 寄存器的讀--- 修改---寫操作,可用來進行處理器模式切換、允許/禁止 IRQ/FIQ 中斷等設置,.

堆棧指令實始化 INITSTACK

MOV R0,LR ;保存返回地址

;設置管理模式堆棧

MSR CPSR_c,#0xD3

LDR SP,StackSvc

;設置中斷模式堆棧

MSR CPSR_c,#0xD2

LDR SP,StackIrq

ARM 偽指令

ARM 偽指令不是 ARM 指令集中的指令,只是為了編程方便編譯器定義了偽指令,使用 時可以像其它 ARM 指令一樣使用,但在編譯時這些指令將被等效的 ARM 指令代替.ARM 偽 指令有四條,分別為 ADR 偽指令,ADRL 偽指令,LDR 偽指令,NOP 偽指令.

X ADR

小范圍的地址讀取偽指令.ADR 指令將基於 PC 相對偏移的地址值讀取到寄存器中. 在匯編編譯源程序時,ADR 偽指令被編譯器替換成一條合適的指令.通常,編譯器用一條 ADD 指令或 SUB 指令來實現該 ADR 偽指令的功能,若不能用一條指令實現,則產生錯誤, 編譯失敗.

ADR 偽指令格式如下 ADR{cond} register,exper

其中 register 加載的目標寄存器

exper 地址表達式.當地址值是非字地齊時,取值范圍-255~255 字 節之間;當地址是字對齊時,取值范圍-1020~1020 字節之間. 對於基於 PC 相對偏移的地址值時,給定范圍是相對當前指 令地址后兩個字處(因為 ARM7TDMI 為三級流水線).

ADR 偽指令舉例如下;

LOOP MOV R1,#0xF0

ADR R2,LOOP ;將 LOOP 的地址放入 R2

ADR R3,LOOP+4 可以用 ADR 加載地址,實現查表:

ADR R0,DISP_TAB ;加載轉換表地址

LDRB R1,[R0,R2] ;使用 R2 作為參數,進行查表

… DISP_TAB

DCB 0Xc0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90

X ADRL

中等范圍的地址讀取偽指令.ADRL 指令將基於 PC 相對偏移的地址值或基於寄存器相對偏移的地址值讀取到寄存器中,比 ADR 偽指令可以讀取更大范圍的地址。在匯編編

譯源程序時,ADRL 偽指令被編譯器替換成兩個條合適的指令。若不能用兩條指令實現

ADRL 偽指令功能,則產生錯誤,編譯失敗。ADRL 偽指令格式如下: ADR{cond} register,exper

其中:register 加載的目標寄存器。

expr 地址表達式。當地址值是非字對齊時,取范圍-64K~64K 字節 之間;當地址值是字對齊時,取值范圍-256K~256K 字節之間。

ADRL 偽指令舉例如下; ADRL R0,DATA_BUF

ADRL R1 DATA_BUF+80

… DATA_BUF

SPACE 100 ;定義 100 字節緩沖區

可以且用 ADRL 加載地址,實現程序跳轉,中等范圍地址的加載

ADR LR,RETURNI ;設置返回地址

ADRL R1 Thumb_Sub+1;取得了 Thumb 子程序入口地址,且 R1的0 位置1

BX R1 ;調用 Thumb 子程序,並切換處理器狀態 RETURNI

… CODE16

Thumb_Sub

MOV R1,#10

X LDR

大范圍的地址讀取偽指令.LDR 偽指令用於加載 32 位的立即數或一個地址值到指定 寄存器.在匯編編譯源程序時,LDR 偽指令被編譯器替換成一條合適的指令.若加載的常 數未超出 MOV 或 MVN 的范圍,則使用 MOV 或 MVN 指令代替該 LDR 偽指令,否則匯編器將常

量放入字池,並使用一條程序相對偏移的 LDR 指令從文字池讀出常量.LDR 偽指令格式如

下;

LDR{cond} register,=expr/label_expr

其中 register 加載的目標寄存器

expr 32 位立即數.

label_expr 基於 PC 的地址表達式或外部表達式. LADR 偽指令舉例如下.

LDR R0,=0x123456 ;加載 32 位立即數 0x12345678

LDR R0,=DATA_BUF+60 ;加載 DATA_BUF 地址+60

LTORG ;聲明文字池

偽指令 LDR 常用於加載芯片外圍功能部件的寄存器地址(32 位立即數),以實現各種 控制操作

加載 32 位立即數

LDR

R0,=IOPIN

;加載 GPIO 寄存器 IOPIN 的地址

LDR

R1,[R0]

;讀取 IOPIN 寄存器的值

LDR

R0,=IOSET

LDR

R1,=0x00500500

STR

R1,[R0]

;IOSET=0x00500500

從 PC 到文字池的偏移量必須小於 4KB

與 ARM 指令的 LDR 相比,偽指令的 LDR 的參數有“=”號

X NOP

空操作偽指令.NOP 偽指令在匯編時將會被代替成 ARM 中的空操作,比如可能為 MOV,R0,R0 指令等,NOP 偽指令格式如下

NOP

NOP 可用於延時操作.

軟件延時

… DELAY1

NOP

NOP NOP

SUBS R1,R1,#1

BNE DELAY1

Thumb 指令集

Thumb 指令可以看作是 ARM 指令壓縮形式的子集,是針對代碼密度的問題而提出 的,它具有 16 位的代碼密度.Thumb 不是一個完整的體系結構,不能指望處理只執行 Thumb指令而不支持ARM指令集.因此,Thumb指令只需要支持通用功能,必要時可以借助 於完善的 ARM 指令集,比如,所有異常自動進入 ARM 狀態.

在編寫 Thumb 指令時,先要使用偽指令 CODE16 聲明,而且在 ARM 指令中要使用 BX 指令跳轉到 Thumb 指令,以切換處理器狀態.編寫 ARM 指令時,則可使用偽指令 CODE32 聲明.

Thumb 指令集與 ARM 指令集的區別

Thumb 指令集沒有協處理器指令,信號量指令以及訪問 CPSR 或 SPSR 的指令,沒有乘 加指令及 64 位乘法指令等,且指令的第二操作數受到限制;除了跳轉指令 B 有條件執行 功能外,其它指令均為無條件執行;大多數 Thumb 數據處理指令采用 2 地址格式.Thumb 指令集與 ARM 指令的區別一般有如下幾點:

A 跳轉指令

程序相對轉移,特別是條件跳轉與 ARM 代碼下的跳轉相比,在范圍上有更多的限制, 轉向子程序是無條件的轉移.

A 數據處理指令 數據處理指令是對通用寄存器進行操作,在大多數情況下,操作的結果須放入其中

一個操作數寄存器中,而不是第 3 個寄存器中.

數據處理操作比 ARM 狀態的更少,訪問寄存器 R8~R15 受到一定限制.

除 MOV 和 ADD 指令訪問器 R8~R15 外,其它數據處理指令總是更新 CPSR 中的 ALU 狀態標志. 訪問寄存器 R8~R15 的 Thumb 數據處理指令不能更新 CPSR 中的 ALU 狀態標志. A 單寄存器加載和存儲指令

在 Thumb 狀態下,單寄存器加載和存儲指令只能訪問寄存器 R0~R7

A 批量寄存器加載和存儲指令

LDM 和 STM 指令可以將任何范圍為 R0~R7 的寄存器子集加載或存儲.

PUSH 和 POP 指令使用堆棧指令 R13 作為基址實現滿遞減堆棧.除 R0~R7 外,PUSH 指

令還可以存儲鏈接寄存器 R14,並且 POP 指令可以加載程序指令 PC

Thumb 存儲器訪問指令

Thumb 指令集的 LDM 和 SRM 指令可以將任何范圍為 R0~R7 的寄存器子集加載或存儲. 批量寄存器加載和存儲指令只有 LDMIA,STMIA 指令,即每次傳送先加載/存儲數據,然后 地址加 4.對堆棧處理只能使用 PUSH 指令及 POP 指令.

Thumb 存儲器訪問指令

助記符

說明 操作

影響標志

LDR Rd,[Rn,#immed_5×4]

加載字數據

Rd←[Rm,#immed_5×4],Rd,Rn 為 R0~R7

LDRH Rd,[Rn,#immed_5×2]

加載無符半字數據

Rd←[Rm,#immed_5×2],Rd,Rn 為 R0~R7

LDRB Rd,[Rn,#immed_5×1]

加載無符字節數據

Rd←[Rm,#immed_5×1],Rd,Rn 為 R0~R7

STR Rd,[Rn,#immed_5×4]

存儲字數據

Rn,#immed_5×4Rd←Rd,Rn 為 R0~R7

STRH Rd,[Rn,#immed_5×2]

存儲無符半遼數據

Rn,#immed_5×2]Rd←Rd,Rn 為 R0~R7

STRB Rd,[Rn#immed_5×1]

存儲無符字節數據

Rn,#immed_5×1]Rd←Rd,Rn 為 R0~R7

LDR Rd,[Rn,Rm]

加載字數據

Rd←[Rn,Rm],Rd,Rn,Rm 為 R0~R7

LDRH Rd,[Rn,Rm]

加載無符半字數據

Rd←[Rn,Rm],Rd,Rn,Rm 為 R0~R7

LDRB Rd,[Rn,Rm]

加載無符字節數據

Rd←[Rn,Rm],Rd,Rn,Rm 為 R0~R7

LDRSH Rd[Rn,Rm]

加載有符半字數據

Rd←[Rn,Rm],Rd,Rn,Rm 為 R0~R7

LDRSB Rd[Rn,Rm]

加載有符字節數據

Rd←[Rn,Rm],Rd,Rn,Rm 為 R0~R7

STR Rd,[Rn,Rm]

存儲字數據

[Rn,Rm]←Rd,Rd,Rn,Rm 為 R0~R7

STRH Rd,[Rn,Rm]

存儲無符半字數據

[Rn,Rm]←Rd,Rd,Rn,Rm 為 R0~R7

STRB Rd,[Rn,Rm]

存儲無符字節數據

[Rn,Rm]←Rd,Rd,Rn,Rm 為 R0~R7

LDR Rd,[PC,#immed_8×4]

基於 PC 加載字數據

Rd←{PC,#immed_8×4]Rd 為 R0~R7

LDR Rd,label

基於 PC 加載字數據

Rd←[label],Rd 為 R0~R7

LDR Rd,[SP,#immed_8×4]

基於 SP 加載字數據

Rd←{SP,#immed_8×4]Rd 為 R0~R7

STR Rd,[SP,#immed_8×4]

基於 SP 存儲字數據

{SP,#immed_8×4]←Rd,Rd 為 R0~R7

LDMIA Rn{!}reglist

批量(寄存器)加載

regist←[Rn…],Rn 回存等(R0~R7)

STMIA Rn{!}reglist

批量(寄存器)加載

[Rn…]←reglist,Rn 回存等(R0~R7)

PUSH {reglist[,LR]}

寄存器入棧指令

[SP…]←reglist[,LR],SP 回存等(R0~R7,LR)

POP {reglist[,PC]}

寄存器入棧指令

reglist[,PC]←[SP…],SP 回存等(R0~R7,PC)

X LDR STR

立即數偏移的LDR和STR指令.存儲器的地址以一個寄存器的立即數偏移指明.指令 格式如下:

LDR Rd,[Rn,#immed_5×4];加載指定地址上的數據(字),放入 Rd 中

STR Rd,[Rn,#immed_5×4];存儲數據(字)到指定地址的存儲單元,要存儲數據在 Rd 中 LDRH Rd,[Rn,#immed_5×4];加載半字數據,放入 Rd 中,即 Rd 低 16 位有效,高 16 位清零 STRH Rd,[Rn,#immed_5×4];存儲半字數據,要存儲的數據在 Rd,最低 16 位有效 LDRB Rd,[Rn,#immed_5×4];加載字節數據,放入 Rd 中,即 Rd 最低字節有效,高 24 位清零 STRB Rd,[Rn,#immed_5×4];存儲字節數據,要存儲的數據在 Rd,最低字節有效 其中 Rd 加載或存儲的寄存器.必須為 R0~R7.

Rn 基址寄存器.必須為 R0~R7.

immed_5×N 偏移量.它是一個無符立即數表達式,其取值為(0~3)×N 立即數偏移的半字和字節加載是無符號的.數據加載到 Rd 的最低有效半字或字

節,Rd 的其余位補 0.

地址對准一一字傳送時,必須保證傳送地址為 32 位對准.半字傳送時,必須保證傳送地址為 16 位對准

立即數偏移的 LDR 和 STR 指令舉例如下; LDR R0,[R1,#0x4]

STR R3,[R4]

LDRH R5,[R0,#0x02] STRH R1,[R0,#0x08] LDRB R3,[R6,#20] STRB R1,[R0,#31]

寄存器偏移的 LDR 和 STR 指令.存儲器的地址用一個寄存器的基於寄存器偏移來指明.指令格式如下,

LDR

Rd,[Rn,Rm]

;加載一個字數據

STR

Rd,[Rn,Rm]

;存儲一個字數據

LDRH

Rd,[Rn,Rm]

;加載一個無符半字數據

STRH

Rd,[Rn,Rm]

;存儲一個無符半字數據

LDRB

Rd,[Rn,Rm]

;加載一個無符字節數據

STRB

Rd,[Rn,Rm]

;存儲一個無符字節數據

LDRSH

Rd,[Rn,Rm]

;加載一個有符半字數據

LDRSB

Rd,[Rn,Rm]

;存儲一個有符半字數據

其中:

Rd

加載或存儲的寄存器.必須為 R0~R7

Rn

基址寄存器.必須為 R0~R7

Rm

內含偏移量的寄存器.必須為 R0~R7.

寄存器偏移的半字和字節加載可以是有符號或無符號的,數據加載到 Rd 的其余位 拷貝符號位.

地址對准—字傳送時,必須保證傳送地址為 32 位對准.半字傳送時,必須保證傳送 地址為 16 位對准.

寄存器偏移的 LDR 和 STR 指令舉例如下; LDR R3,[R1,R0]

STR R1,[R0,R2] LDRH R6,[R0,R1] STRH R0,[R4,R5] LDRB R2,[R5,R1] STRB R1,[R3,R2] LDRSH R7,[R6,R3] LDRSB R5,[R7,R2]

PC 或 SP 相對偏移的 LDR 和 STR 指令.用 PC 或 SP 寄存器中的值的立即數偏移來指 明存儲器的地址.指令格式如下.

LDR Rd,[PC,#immed_8×4] LDR Rd,label

LDR Rd,[SP,#immed_8×4] STR Rd,[SP,#immed_8×4]

其中: Rd 加載或存儲的寄存器.必須為 R0~R7

immed_8×4] 偏移量.它是一個無符立即數表達式,其取值為(0~255)×4

label 程序相對偏移表達式.label 必須在當前指令之后 IK 字節范圍內.

地址對准—地址必須是 4 的整數倍.

PC 或 SP 相對偏移的 LDR 和 STR 指令舉例如下;

LDR

R0,[PC,#0x08]

;讀取 PC+0x08 地址上的字數據,保存到 R0 中

LDR

R7,LOCALDAT

;讀取 LOCALDAT 地址上的字數據,保存到 R7 中

LDR

R3,[SP,#1020]

;讀取 SP+1020 地址上的字數據,保存到 R3 中

STR

R2,[SP]

;存儲 R2 寄存器的數據到 SP 指向的存儲單元(偏移量為 0)

X PUSH POP

寄存器入棧及出棧指令.實現低寄存器和可選的 LR 寄存器入棧寄存器和可選的 PC 寄存器出棧操作,堆棧地址由 SP 寄存設置,堆棧是滿遞減堆棧.指令格式如下;

PUSH {reglist[,LR]}

POP {reglist[,PC]}

其中

reglist

入棧/出棧低寄存器列表,即 R0~R7

LR

入棧時的可選寄存器

PC

出棧時的可選寄存器

寄存器入棧及出棧指令舉例如下;

PUSH

{R0-R7,LR}

;將低寄存器 R0~R7 全部入棧,LR 也入棧

POP

{R0-R7,PC}

;將堆棧中的數據彈出到低寄存器 R0~R7 及 PC 中

X LDMIA STMIA

批量加載/存儲指令可以實現在一組寄存器和一塊連續的內存單元之間傳輸數 據.Thumb 指令集批量加載/存儲指令為 LDMIA 和 STMIA,LDMIA 為加載多個寄存器;STM 為存儲多個寄存器,允許一條指令傳送 8 個低寄存器的任何子集.指令格式如下;

LDMIA Rn!,reglist

STMIA Rn!,reglist

其中 Rn 加載/存儲的起始地址寄存器.Rn 必須為 R0~R7

Reglist 加載/存儲的寄存器列表.寄存器必須為 R0~R7

LDMIA/STMIA 的主要用途是數據復制,參數傳送等,進行數據傳送時,每次傳送后地

址加 4.若 Rn 在寄存器列表中,對於 LDMIA 指令,Rn 的最終值是加載的值,而不是增加后的地址;對於 STMIA 指令,在 Rn 是寄存器列表中的最低數字的寄存器,則 Rn 存儲的值為 Rn 在初值,其它情況不可預知.

批量加載/存儲指令舉例如下;

LDMIA R0,{R2-R7} ;加載 R0 指向的地址上的多字數據,保存到 R2~R7 中,R0 的值更新.

STMIA R1!,{R2-R7};將 R2~R7 的數據存儲到 R1 指向的地址上,R1 值更新.

Thumb 數據處理指令

大多數 Thumb 處理指令采用 2 地址格式,數據處理操作比 ARM 狀態的更少,訪問寄存 器 R8~R15 受到一定限制.

Thumb 數據處理指令

助記符

說明

操作

影響標志

MOV Rd,#expr

數據轉送

Rd←expr,Rd 為 R0~R7

影響 N,Z

MOV Rd,Rm

數據轉送

Rd←Rm,Rd、Rm 均可為 R0~R15

RdT 和 Rm 均 為

R0~ R7 時,影響 N,Z,清零 C,V

MVN Rd,Rm

數據非傳送指令

Rd←(~Rm),Rd,Rm 均為 R0~R7

影響 N,Z

NEG Rd,Rm

數據取負指令

Rd←(-Rm),Rd,Rm 均為 R0~R7

影響 N,Z,C,V

ADD Rd.Rn,Rm

加法運算指令

Rd←Rn+Rm,Rd,Rn,Rm 均為 R0~R7

影響 N,Z,C,V

ADD Rd.Rn,#expr3

加法運算指令

Rd←Rn+expr#,Rd,Rn 均為 R0~R7

影響 N,Z,C,V

ADD Rd,#expr8

加法運算指令

Rd←Rd+expr8,Rd 為 R0~R7

影響 N,Z,C,V

ADD Rd,Rm

加法運算指令

Rd←Rd+Rm,Rd,Rm 均可為 R0~R15

Rd和 Rm 均為 R0~

R7 時 , 影 響 N,Z,C,V

ADD Rd,Rp#expr

SP/PC 加法運算指令

Rd←SP+expr 或 PC+expr,Rd 為 R0~R7

ADD SP,#expr

SP 加法運算指令

SP←SP+expr

SUB Rd,Rn,Rm

減法運算指令

Rd←Rn-Rm,Rd、Rn、Rm 均為 R0~R7

影響 N,Z,C,V

SUB Rd,Rn#expr3

減法運算指令

Rd←Rn-expr3,RdRn 均為 R0~R7

影響 N,Z,C,V

SUB Rd,#expr8

減法運算指令

RD←Rd-expr8,Rd 為 R0~R7

影響 N,Z,C,V

SUB SP,#expr

SP 減法運算指令

SP←SP-expr

ADC Rd,Rm

帶進位加法指令

Rd←Rd+Rm+Carry,Rd、Rm 為 R0~R7

影響 N,Z,C,V

SBC Rd,Rm

帶位減法指令

Rd←Rd-Rm-(NOT)Carry,Rd、Rm 為 R0~R7

影響 N,Z,C,V

MUL Rd,Rm

乘法運算指令

Rd←Rd*Rm,Rd、Rm 為 R0~R7

影響 N,Z,

AND Rd,Rm

邏輯與操作指令

Rd←Rd&Rm,Rd、Rm 為 R0~R7

影響 N,Z,

ORR Rd,Rm

邏輯或操作指令

Rd←Rd|Rm,Rd、Rm 為 R0~R7

影響 N,Z,

EOR Rd,Rm

邏輯異或操作指令

Rd←Rd^Rm,Rd、Rm 為 R0~R7

影響 N,Z,

BIC Rd,Rm

位清除指令

Rd←Rd&(~Rm),Rd、Rm 為 R0~R7

影響 N,Z,

ASR Rd,Rs

算術右移指令

Rd←Rd 算術右移 Rs 位,Rd,Rs 為 R0~R7

影響 N,Z,C,

ASR Rd,Rm#expr

算術右移指令

Rd←Rm 算術右移 expr 位,Rd、Rm 為 R0~R7

影響 N,Z,C,

LSL Rd,Rs

邏輯左移指令

Rd←Rd<<Rs,Rd、Rs 為 R0~R7

影響 N,Z,C,

LSL Rd,Rm,#expr

邏輯左移指令

Rd←Rm<<expr,Rd、Rm 為 R0~R7

影響 N,Z,C,

LSR Rd,Rs

邏輯右移指令

Rd←Rd>>Rs,Rd、Rs 為 R0~R7

影響 N,Z,C,

LSR Rd,Rm,#expr

邏輯右移指令

Rd←Rm>>mexpr,Rd、Rm 為 R0~R7

影響 N,Z,C,

ROR Rd,Rs

循環右移指令

Rd←Rm 循環右移 Rs 位,Rd、Rs 為 R0~R7

影響 N,Z,C,

CMP Rn,Rm

比較指令

狀態標←Rn-Rm,Rn、Rm 為 R0~R15

影響 N,Z,C,V

CMP Rn,#expr

比較指令

狀態標←Rn-expr,Rn 為 R0~R7

影響 N,Z,C,V

CMN Rn,Rm

負數比較指令]

狀態標←Rn+Rm,Rn、Rm 為 R0~R7

影響 N,Z,C,V

TST Rn,Rm 位測試指令 狀態標←Rn&Rm,Rn、Rm 為 R0~R7 影響 N,Z,C,V

clip_image019數據傳送指令

X MOV

數據傳送指令.將 8 位立即數或寄存器(operand2)傳送到目標寄存器(Rd).指令格 式如下;

MOV Rd,#expr

MOV Rd,Rm

其中 Rd 目標寄存器.MOV Rd#expr 時,必須在 R0~R7 之間

exper 8 位立即數,即 0~255

Rm 源寄存器.為 R0~R15 條件碼標志:

MOV Rd,#expr 指令會更新N和Z 標志,對標志C和V 無影響.而 MOV,Rd,Rm 指令,若 Rd 或 Rm 是高寄存器(R8~R15),則標志不受影響,若 Rd 或 Rm 都是低寄存器(R0~R7),則會更新 N 和 Z,且清除標志C和 V.

MOV 指令舉例如下

MOV

R1,#0x10

;R1=0x10

MOV

R0,R8

;R0=R8

MOV

PC,LR

;PC=LR,子程序返回

X MVN

數據非傳送指令.將寄存器 Rm 按位取反后傳送到目標寄存器(Rd).指令格式如下: MVN Rd,Rm

其中: Rd 目標寄存器.必須在 R0~R7 之間 Rm 源寄存器.必須在 R0~R7 之間

條件碼標志:

指令會更新N和Z 標志,對標志C和V 無影響. MVN 指令舉例如下

MVN R1,R2 ;將 R2 取反結果存到 R1

X NEG

數據取負指令.將寄存器 Rm 乘以-1 后傳送到目標寄存器(Rd).指令格式如下: NEG Rd,Rm

其中: Rd 目標寄存器.必須在 R0~R7 之間 Rm 源寄存器.必須在 R0~R7 之間

條件碼標志

指令會更新 N,Z,C,V 和標志. NEG 指令舉例如下

NEG R1,R0, ;R1=-R0

算術邏輯運算指令

X ADD

加法運算指令.將兩個數據相加,結果保存到 Rd 寄存器. 低寄存器的 ADD 指令的指令格式如下

ADD Rd,Rn,Rm

ADD Rd,Rn,#expr3

ADD Rd,#expr8

其中 Rd 目標寄存器.必須在 R0~R7 之間.

Rn 第一個操作數寄存器.必須在 R0~R7 之間. Rm 第二個操作數寄存器.必須在 R0~R7 之間. expr3 3 位立即數,即 0~7

expr8 8 位立即數,即 0~255. 條件碼標志:指令會更新 N、Z、C 和 V 標志. 高或低寄存器的 ADD 指令的指令格式如下: ADD Rd,Rm

其中 Rd 目標寄存器,也是第一個操數寄存器.

Rm 第二個操作數寄存器

條件碼標志:若 Rd 或 Rm 都是低寄存器(R0~R7),指令會更新 N、Z、C 和 V 標志.其它 情況不影響條件碼標志.

PC 或 SP 相對偏移的 ADD 指令指令格式如下:

ADD Rd,Rp,#expr

其中 Rd 目標寄存器.必須在 R0~R7 之間 Rp PC 或 SP,第一個操作數寄存器. expr 立即數,在 0~1020 范圍內.

條件碼標志:不影響條件碼標志.

SP 操作的 ADD 指令的指令格式如下 ADD SP,#expr

ADD SP,SP,#expr

其中 SP 目標寄存器,也是第一個操作數寄存器.

expr 立即數,在-508~+508 之間的 4 的整數倍的數條件碼標志:不影響條件碼標志.

ADD 指令舉例如下

ADD R1,R1,R0 ;R1=R1+R0

ADD R1,R1,#7 ;R1=R1+7

ADD R3,#200 ;R3=R3+200

ADD R3,R8 ;R3=R3+R8

ADD R1,SP,#1000 ;R1=SP+1000

ADD SP,SP,#-500 ;SP=SP-500

X SUB

減法運算指令.將兩個數相減,結果保存到 Rd 中. 低寄存器的 SUB 指令的指令格式如下;

SUB Rd,Rn,Rm

SUB Rd,Rn,#expr3

SUB Rd,#expr8

其中

Rd

目標寄存器.必須在 R0~R7 之間

Rn

第一個操作數寄存器.必須在 R0~R7 之間

Rm

第一個操作數寄存器.必須在 R0~R7 之間

expr3

3 位立即數,即 0~7

expr8 8 位立即數.即 0~255

條件碼標志:指令會更新 N、Z、C 和 V 標志. SP 操作的 SUB 指令的指令格式如下

SUB SP,#expr

SUB SP,SP,#expr

其中 SP 目標寄存器,也是第一個操作數據寄存器. expr 立即數,在-508~+508 之間的 4 的整數倍的數

條件碼標志:不影響條件碼標志

SUB 指令舉例如下

SUB

R0,R2,R1,

;R0=R2-R1

SUB

R2,R1,#1

;R2=R1-1

SUB

R6,#250

;R6=R6-250

SUB

SP,#380

;SP=SP-380

X ADC

帶進位加法指令.將 Rm 的值與 Rd 的值相加,再加上 CPSR 中的 C 條件標志位,結果保 存到 Rd 寄存器.指令格式如下

ADC Rd,Rm

其中 Rd 目標寄存器,也是第一個操作數寄存器.必須在 R0~R7 之間 Rm 第二個操作數寄存器.必須在 R0~R7 之間

條件碼標志:指令會更新 N、Z、C 和 V 標志. ADC 指令舉例如下;

ADD R0,R0,R2,

ADC R1,R1,R3 ;使用 ADC 實現 64 位加法,(R1,R0)+(R3,R2)

X SBC

帶進位減法指令.用寄存器 Rd 減去 Rm,再減去 CPSR 中的 C 條件標志的非(即若 C 標 志清零,則結果減去 1),結果保存到 Rd 中.指令格式如下

SBC Rd,Rm

其中 Rd 目標寄存器,也是第一個操作數寄存器.必須在 R0~R7 之間

Rm 第二個操作數寄存器.必須在 R0~R7 之間]

條件碼標志:指令會更新 N、Z、C和V 標志 SBC 指令舉例如下

SUB R0,R0,R2

SUB R1,R1,R3 ;使用 SBC 實現 64 位減法,(R1,R0)=(R1,R0)-(R3,R2)

X MUL

乘法運算指令.用寄存器 Rd 乘以 Rm,結果保存到 Rd 中.指令格式如下; MUL Rd,Rm

其中 Rd 目標寄存器,也是第一個操作數寄存器.必須在 R0~R7 之間 Rm 第二操作數寄存器.必須在 R0~R7 之間

條件碼標志:指令會更新N和Z 標志 MUL 指令舉例如下

MUL R2,R0,R1 ;R2=R0*R1

X AND

邏輯與操作指令.將寄存器 Rd 的值與寄存器 Rm 值按位作邏輯與操作,結果保存到 Rd 中.指令格式如下

AND Rd,Rm

其中 Rd 目標寄存器,也是第一個操作數寄存器.必須在 R0~R7 之間 Rm 第二個操作數寄存器.必須在 R0~R7 之間

條件碼標志:指令會更新N和Z 標志 AND 指令舉例如下;

MOV R1,#0x0F

AND R0,R1 ;R0=R0 & R1

X ORR

邏輯或操作指令.將寄存器 Rd 與寄存器 Rn 的值按位作邏輯或操作,結果保存到 Rd

中.指令格式如下:

ORR

Rd,Rm

其中

Rd

目標寄存器,也是第一個操作數寄存器.必須在 R0~R7 之間

Rm 第二個操作數寄存器.必須在 R0~R7 之間

條件碼標志:指令會更新N和Z 標志 ORR 指令舉例如下

MOV

R1,#0x03

ORR

R0,R1

;R0=R0|R1

X EOR

邏輯異或操作指令.寄存器Rd的值與寄存器Rn的值按位作邏輯異或操作,結果保存 到 Rd 中,指令格式如下;

EOR Rd,Rm

其中 Rd 目標寄存器,也是第一個操作數寄存器.必須在 R0~R7 之間 Rm 第二個操作數寄存器.必須在 R0~R7 之間

條件碼標志:指令會更新N和Z 標志

EOR 指令舉例如下

MOV

R2,#0Xf0

EOR

R3,R2,

;R3=R3^R2

X BIC

位清除指令.將寄存器Rd的值與寄存器Rm的值反碼按位作邏輯與操作.結果保存到 Rd 中,指令格式如下

BIC Rd,Rm

其中 Rd 目標寄存器,也是第一個操作數寄存器.必須在 R0~R7 之間.

Rm 第二個操作數寄存器.必須在 R0~R7 之間條件碼標志:指令會更新N和Z 標志

BIC 指令舉例如下:

MOV

R1,#0x80

BIC

R3,R1

;將 R1 的最高位清零,其它位不變

X ASR

算術右移指令.數據算術右移,將符號位拷貝到空位,移位結果保存到 Rd 中,指令格 式如下;

ASR Rd,Rs

ASR Rd,Rm,#expr

其中 Rd 目標寄存器,也是第一個操作數寄存器.必須在 R0~R7 之間 Rs 寄存器控制移位中包含移位量的寄存器.必須在 R0~R7 之間 Rm 立即數移位的源寄存器.必須在 R0~R7 之間

expr 立即數移位量,值為 1~32

條件碼標志:指令會更新 N、Z 和 C 標志(若移位量為零,則不影響 C 標志) ASR 指令舉例如下

ASR R1,R2, ASR R3,R1,#2

若移位量為 32,則 Rd 清零,最后移出的位保留在標志 C 中,若移位量大於 32,則 Rd

和標志 C 均被清零;若移位量為 0,則不影響 C 標志

X LSL

邏輯左移指令.數據邏輯左移,空位清零,移位結果保存到 Rd 中,指令格式如下 LSL Rd,Rs

LSL Rd,Rm,#expr

其中 Rd 目標寄存器,也是第一個操作數寄存器.必須在 R0~R7 之間 Rs 寄存器控制移位中包含位量的寄存器.必須在 R0~R7 之間 Rm 立即數移位的源寄存器.必須在 R0~R7 之間

expr 立即數移位量,值為 1~31

條件碼標志:指令會更新 N、Z 和 C 標志(若移位量為零,則不影響 C 標志) LSL 指令舉例如下

LSL R6,R7

LSL R1,R6,#2

若移位量為 32,則 Rd 清零,最后移出的位保留在標志 C 中;若移位量大於 32,則 Rd

和標志 C 均被清零;若移位量為 0,則不影響 C 標志

X LSR

邏輯左移指令.數據邏輯左移,空位清零,移位結果保存到 Rd 中.指令格式如下

LSR Rd,Rs

LSR Rd,Rm,#expr

其中 Rd 目標寄存器,也是第一個操作數寄存器.必須在 R0~R7 之間 Rs 寄存器控制移位中包含移位量的寄存器.必須在 R0~R7 之間 Rm 立即數移位的源寄存器.必須在 R0~R7 之間

expr 立即數移位量,值為 1~32

條件碼標志:指令會更新 N、Z 和 C 標志(若移位量為零,則不影響 C 標志) LSR 指令舉例如下

LSR R3,R0

LSR R5,R2,#2

若移位量為 32,則 Rd 清零,最后移出的位保留在標志 C 中;若移位量大於 32,則 Rd

和標志 C 均被清零,若移位量為 0,則不影響 C 標志.

X ROR

循環右移指令.數據循環右移,寄存器右邊移出的位循環移回到左邊,移位結果保存 到 Rd 中,指令格式如下

ROR Rd,Rs

其中 Rd 目標寄存器.也是第一個操作數寄存器.必須在 R0~R7 之間 Rs 寄存器控制移位中包含移位量的寄存器.必須在 R0~R7 之間

條件標志:指令會更新 N,Z,C 的標志(若移位量為零,則不影響 C 標志). ROR 指令舉例如下

ROR R2,R3

比較指令

X CMP

比較指令.指令使用寄存器 Rn 的值減去第二個操作數的值,根據操作的結果理新 CPSR 中的相應條件標志位.指令格式如下

CMP Rn,Rm

CMP Rn,#expr

其中

Rn

第一個操作數寄存器.對 CMP,Rn#expr 指令,Rn 在 R0~R7 之間;對於

CMP,Rn,Rm 指令在 Rn 在 R0~R15 之間

Rm

第二個操作數寄存器.Rm 在 R0~R15 之間

expr

立即數,值為 0~255

條件碼標志:指令會更新 N、Z、C和V 標志 CMP 指令舉例如下

CMP R1,#10 ;R1 與 10 比較,設置相關標志位 CMP R1,R2 ;R1 與 R2 比較,設置相關標志位

X CMN

負數比較指令.指令使用寄存器 Rn 的值加上寄存器 Rm 的值,根據操作的結果理新 CPSR 中的相應條件標志.位指令格式如下

CMN Rn,Rm

其中 Rn 第一個操作數寄存器,必須在 R0~R7 之間 Rm 第二個操作數寄存器.必須在 R0~R7 之間

條件碼標志:指令會更新 N、Z、C 和 V 標志. CMN 指令舉例如下

CMM R0,R2 ;R0 與 R2 進行比較

X TST

位測試指令.指令將寄存器Rn的值與寄存器Rm的值按位作邏輯與操作.根據操作的 結果理新 CPSR 相應條件標志位.指令格式如下.

TST Rn,Rm

其中 Rn 第一個操作數寄存器.必須在 R0~R7 之間 Rm 第二個操作數寄存器.必須在 R0~R7 之間

條件碼標志:指令會更新 N、Z、C和V 標志 TST 指令舉例如下

MOV R0,#x01

TST R1,R0, ;判斷 R1 的最低位是否為 0

Thumb 跳轉指令

助記符

說明

操作

條件碼位置

B label

跳轉指令

PC←label

B{cond}

BL label

帶鏈接的跳轉指令

LR←PC←4,PC←label

BX Rm

帶狀態切換的跳轉指令

PC←label 切換處理器狀態

X B

跳轉指令.跳轉到指定的地址執行程序.這是 Thumb 指令集中的惟一的有條件執行 指令.指令格式如下

B{cond} label 跳轉指令 B 舉例如下 B WAITB

BEQ LOOP1

若使用 cond 則 label 必須在當前指令的-252~+256 字節范圍內;若指令是無條件的, 則跳轉指令 label 必須在當前指令的±2K 字節范圍內

X BL

帶鏈接的跳轉指令.指令先將下一條指令的地址拷貝到 R14(即 LR)鏈接寄存器中, 然后跳轉到指定地址運行程序.指令格式如下:

BL label

帶鏈接的跳轉指令 BL 舉例如下 BL DELAYI

機器級轉指令 BL 限制在當前指令的±4Mb 的范圍內.(必要時,ARM 鏈接器插入代碼 以允許更長的轉移.)

X BX

帶狀態切換的跳轉指令.跳轉到 Rm 指定的地址執行程序.若 Rm 的位[0]為 0,則 Rm 的位於也必須為 0,跳轉時自動將 CPSR 中的標志 T 復位,即把目標地址的代碼解釋為 ARM 代碼.指令格式

BX Rm

帶狀態切換的跳轉指令 BX 舉例如下.

ADR R0,ArmFun

BX R0 ;跳轉到R0指定的地址,並根據R0的最低位來切換處理器狀態.

Thumb 雜項指令

X SWI

軟中斷指令.SWI 指令用於產生軟中斷,從而實現在用戶模式變換到管理模式.CPSR 保存到管理模式的 SPSR 中,執行轉移到 SWI 向量.在其它模式下也可使用 SWI 指令,處理 器同樣地切換到管理模式.

指令格式如下. SWI immed_8

其中 immed_8 8 位立即數,值為 0~255 之間的整數. SWI 指令舉例如下

SWI 1 ;軟中斷,中斷立即數為 0

SWI 0x55 ;軟中斷,中斷立即數為 0x55

使用 SWI 指令時,通常使用以下兩種方法進行傳遞參數,SWI 異常中斷處理程序可以 提供相關的服務,這兩種方法均是用戶軟件協定.SWI 異常中斷處理程序要通過讀取引 起軟中斷的 SWI 指令.以取得 8 位立即數.

1.指令中 8 位的立即數指定了用戶請求的服務類型,參數通過用寄存器傳遞. MOV R0,#34 ;設置子功能號為虎作 34

SWI 18 ;調用 18 號軟中斷

2.指令中的 8 位立即數被忽略,用戶請求的服務類型由寄存器 R0 的值決定,參數通 過其它的通用寄存器傳遞.

MOV R0,#18 ;調用 18 號軟中斷 MOV R1,#34 ;設置子功能號為了 4

SWI 0

Thumb 偽指令

X ADR

小范圍的地址讀取偽指令.ADR 指令將基於 PC 相對偏移的地址值讀取到寄存器 中.ADR 偽指令格式如下.

ADR register,expr

其中 register 加載的目標寄存器.

expr 地址表達式.偏移量必須是正數並小於 1KB.Expr 必須局部定義, 不能被導入.

ADR 偽指令舉例如下

ADR register, expr

其中 register 加載的目標寄存器。

expr 地址表達式。偏移量必須是正數並小說於 1KB。Expr 必須局部 定義,不能被導入。

ADR 偽指令舉例如下: ADR R0,TxtTab

… TxtTab

DCB ”ARM7TDMI”,0

X LDR

大范圍的地址讀取偽指令.LDR 偽指令用於加載 32 位的立即數或一個地址值到指定 寄存器.在匯編編譯源程序時,LDR 偽指令被編譯器替換成一條合適的指令.若加載的常 數未超出 MOV 范圍,則使用 MOV 或 MVN 指令代替 LDR 偽指令,否則匯編器將常量放入文字 池,並使用一條程序相對偏移的 LDR 指令從文字池讀出常量.LDR 偽指令格式如下.

LDR register,=expr/label_expr

其中, register 加載的目標寄存器

expr 32 位立即數.

label_expr 基於 PC 的地址表達式或外部表達式. LADR 偽指令舉例如下;

LDR R0,=0x12345678 ;加載 32 位立即數 0x12345678

LDR R0,=DATA_BUF+60 ;加載 DATA_BUF 地址+60

LTORG ;聲明文字池

從 PC 到文字池的偏移量必須是正數小於是 1KB.

與 Thumb 指令的 LDR 相比,偽指令的 LDR 的參數有“=”號.

X NOP

空操作偽指令.NOP 偽指令在匯編時將會將會被代替成 ARM 中的空操作,比如可能為 MOV,R8,R8 指令等.NOP 偽指令格式如下.

NOP

NOP 可用於延進操作

偽指令

ARM 匯編程序的由機器指令,偽指令和宏指令組成.偽指令不像機器指令那樣在處 理器運行期間由機器執行,而是匯編程序對源程序匯編期間由匯編程序處理.在前面的 指令集章節中,我們已經接觸了幾條常用到的偽指令,如 ADR ,ADRL,LDR,NOP 等,把它們 和指令集一起介紹是因為它們在匯編時會被合適的機器指令代替,實現真正機器指令操 作.宏是一段獨立的程序代碼,它是通過偽指令定義的,在程序中使用宏指令即可調用宏. 當程序被匯編時,匯編程序將對每個調用進行展開,用宏定義取代源程序中的宏指令.

符號定義偽指令

符號定義偽指令用於定義 ARM 匯編程序的變量,對變量進行賦值以及定義寄存器名 稱,該類偽指令如下;

全局變量聲明:GBLA,GBLL 和 GBLS 局部變量聲明:LCLA,LCLL 和 LCLS 變量賦值: SETA,SETL 和 SETS 為一個通用寄存器列表定義名稱:RLIST 為一個協處理器的寄存器定義名稱:CN 為一個協處理定義名稱: CP

為一個 VFP 寄存器定義名稱:DN 和 SN 為一個 FPA 浮點寄存器定義名稱:FN

X GBLAGBLLGBLS

全局變量聲明偽指令.

GBLA 偽指令用於聲明一個全局的算術變量,並將其初始化為 0;

GBLL 偽指令用於聲明一個全局的邏輯變量,並將其初始化為{FALSE};

GBLS 偽指令用於聲明一個全局的字符串變量,並將其初始化為空字符串“”。 偽指令格式;

GBLA variable

GBLL

variable

GBLS

variable

其中

variable

定義的全局變量名,在其作用范圍內必須惟一.全局變量的作

用范圍為包含該變量的源程序. 偽指令應用舉例如下;

GBLL codedbg ;聲明一個全局邏輯變量

codebg SETL {TRUE} ;設置變量為{TRUE}

X LCLALCLLLCLS

局部變量聲明偽指令.用於宏定義的體中.

LCLA 偽指令用於聲明一個局部的算術變量,並將其初始化為 0

LCLL 偽指令用於聲明一個局部的邏輯變量,並將其初始化為{FALSE}

LCLS 偽指令用於聲明一個局部的字符串變量,並將其初始化為空字符串“” 偽指令格式;

LCLA variable LCLL variable LCLS variable

其中 variable 定義的局部變量名。在其作用范圍內必須惟一。局部變量的作用范圍為包含該局部變量只能在宏中進行聲明及使用。

偽指令應用舉例如下;

MACRO ;聲明一個宏 SENDDAT $dat ;宏的原型

LCLA bitno ;聲明一個局部算術變量

bitno SETA 8 ;設置變量值為 8

… MEND

X SETASETLSETS

變量賦值偽指令.用於對已定義的全局變量,局部變量賦值. SETA 偽指令用於給一個全局/局部的算術變量賦值.

SETL 偽指令用於給一個全局/局部的邏輯變量賦值. SETS 偽指令用於給一個全局/局部的字符串變量賦值. 偽指令格式;

variable_a SETA expr_a variable_l SETL expr_l

variable_s SETS expr_s

其中

variable_a

算術變量.用 GBLA,LCLA 偽指令定義的變量.

expr_a

賦值的常數.

variable_l

邏輯變量.用 GBLL,LCLL 偽指令定義的變量.

expr_l

邏輯值,即{TRUE}或{FALSE}.

variable_s

字符串變量.用 GBLS,LCLS 偽指令定義的變量.

expr_s

賦值的字符串.

偽指令應用舉例如下.

GBLS ErrStr

ErrStr SETS “No,semaphone”

X RLIST

RLIST 為一個通用寄存器列表定義名稱.偽指令格式如下:

name RLIST {reglist}

其中 name 要定義的寄存器列表的名稱. reglist 通用寄存器列表.

偽指令應用舉例如下;

LoReg RLIST {R0-R7} ;定義寄存器列表 LoReg

STMFD SP!,LoReg ;保存寄存器列表 LoReg

X CN

CN 為一個協處理器的寄存器定義名稱. 偽指令格式;

name CN expr

其中 name 要定義的協處理器的寄存器名稱.

expr 協處理器的寄存器編號,數值范圍為 0~15. 偽指令應用舉例如下;

MemSet CN l ;將協處理的寄存器 l 名稱定義為 MemSet

X CP

CP 為一個協處理器定義的名稱. 偽指令格式;

name CP expr

其中 name 要定義的協處理器名稱.

expr 協處理器的編號,數值范圍為 0~15. 偽指令應用舉例如下;

DivRun CN 5 ;將協處理器 5 名稱定義為 DivRun

X DNSN

DN 和 SN 為 VFP 的寄存器的名稱定義的偽指令. DN 為一個雙精度原 VFP 寄存器定義名稱.

SN 為一個單精度的 VFP 寄存器定義名稱. 偽指令格式;

name DN expr

name SN expr

其中 name 要定義的 VFP 寄存器名稱.

expr 雙精度的 VFP 寄存器編號為 0~15,單精度的 VFP 寄存器編號為 0~31. 偽指令應用舉例如下;

cdn DN 1 ;將 VFP 雙精度寄存器 1 名稱定義為 cdn rex SN 3 ;將 VFP 單精度寄存器 3 名稱定義為 rex

X FN

FN 為一個 FPA 浮點寄存器定義名稱 偽指令格式;

name FN expr

其中 name 要定義的浮點寄存器名稱. expr 浮點寄存器的編號,值為 0~7

偽指令應用舉例如下;

ibq FN l ;將浮點寄存器 l 名稱定義為 ibq

數據定義偽指令

數據定義偽指令用於數據表定義,文字池定義,數據空間分配等.該類偽指令如下; 聲明一個文字池:LTORG;

定義一個結構化的內存表的首地址:MAP 定義結構化內存表中的一個數據域:FIELD 分配一塊內存空間,並用 0 初始化:SPACE 分配一段字節的內存單元,並用指定的數據初始化:DCB; 分配一段字的內存單元,並用指令的數據初始化:DCD 和 DCDU;

分配一段字的內存單元,將每個單元的內容初始化為該單元相對於靜態基址寄存器的偏移量:DCDO;

分配一段雙字的內存單元,並用雙精度的浮點數據初始化:DCFD 和 DCFDU; 分配一段字的內存單元,並用單精度的浮點數據初始化:DCFS 和 DCFSU;

分配一段字的內存單元,並用單精度的浮點數據初始化,指定內存單元存放的是代

碼,而不是數據:DCI

分配一段雙字的內存單元,並用 64 位整數數據初始化:DCQ 和 DCQU 分配一段半字的內存單元,並用指定的數據初始化:DCW 和 DCWU;

X LTORG

LTORG 用於聲明一個文字池,在使用 LDR 偽指令時,要在適當的地址加入 LTORG 聲明 文字池,這樣就會把要加載的數據保存在文字池內,再用 ARM 的加載指令讀出數據.(若沒有使用 LTORG 聲明文字池,則匯編器會在程序末尾自動聲明.)

偽指令格式: LTORG 偽指令應用舉例如下;

LDR R0,=0x12345678

ADD R1,R1,R0

MOV PC,LR

LTORG ;聲明文字池,此地址存儲 0x12345678

… ;其它代碼

LTORG 偽指令常放在無條件跳轉指令之后,或者子程序返回指令之后,這樣處理器 就不會錯誤地將文字池中的數據當作指令來執行.

X MAP

MAP 用於定義一個結構化的內存表的首地址.此時,內存表的位置計數器{VAR}設置 為該地址值{VAR}為匯編器的內置變量.^與 MAP 同義.

偽指令格式:

MAP expr,{base_register}

其中 expr 數字表達式或程序中的標號.當指令中沒有

base_register 時,expr 即為結構化內存表的首地址.

base_register 一個寄存器.當指令中包含這一項時,結構化內存表的首地

址為 expr 與 base_register 寄存器值的和.

偽指令應用舉例如下;

MAP 0x00,R9 ;定義內存表的首地址為 R9

Timer FIELD 4 ;定義數據域 Timer,長度為 4 字節 Attrib FIELD 4 ;定義數據域 Attrib,長度為 4 字節 String FIELD 100 ;定義數據域 String,長度為 100 字節

ADR R9,DataStart ;設置 R9 的值,即設置結構化的內存表地址 LDR R0,Atrrib ;相當於 LDR,R0,[R9,#4]

MAP 偽指令和 FIELD 偽指令配合使用,用於定義結構化的內存表結構.MAP 偽指令中 的base-register寄存器的值對於其后所有的FIELD偽指令定義的數據域是默認使用的, 直到遇到新的包含 base-register 項的 MAP 偽指令.

X FIELD

FIELD 用於定義一個結構化內存表中的數據域.#與 FIELD 同義. 偽指令格式:

{tabel}

FIELD

expr

其中

label

當指令中包含這一項時,label 的值為當前內存表的位置計數

器{VAR}的值,匯編編譯器處理了這條 FIELD 偽指令后,內存表

計數器的值將加上 expr.

expr

表示本數據域在內存表中所占用的字節數.

偽指令應用舉例如下;

MAP

0x40003000

;內存表的首地址為 0x40003000

count1

FIELD

4

;定義數據域 count1,長度為 4 字節

count2

FIELD

4

;定義數據域 count2,長度為 4 字節

count3

FIELD

4

;定義數據域 count3,長度為 4 字節

LDR

R1,count1

;R1=[0x40003000+0x00]

STR

R1,count2

;[0x40003000+0x00]=R1

MAP,FIELD 偽指令僅僅是定義數據結構,它們並不實際分配內存單元.

X SPACE

SPACE 用於分配一塊內存單元,並用 0 初始化.%與 SPACE 同義. 偽指令格式:

{label} SPACE expr

其中 label 內存塊起始地址標號. expr 所要分配的內存字節數.

偽指令應用舉例如下;

AREA DataRA,DATA,READWROTE ;聲明一數據段,名為 DataRAM DataBuf SPACE 1000 ;分配 1000 字節空間

X DCB

DCB 用於分配一段字節內存單元,並用偽指令中的 expr 初始化.一般可用來定義數 據表格,或文字符串.=與 DCB 同義.

偽指令格式:

{label} DCB expr{,expr}{,expr}… 其中 label 內存塊起始地址標號.

expr 可以為-128~255 的數值或字符串.內存分配的字節數由 expr 個數決定.

偽指令應用舉例如下

DISPTAB DCB 0x33,0x43,0x76,0x12

DCB -120,20,36,55

ERRSTR DCB “Send,data is error!”,0

X DCD DCDU

DCD用於分配一段字內存單元,並用偽指令中的expr初始化.DCD偽指令分配的內存 需要字對齊,一般可用來定義數據表格或其它常數.&與 DCD 同義.

DCDU 用於分配一段字內存單元,並用偽指令中的 expr 初始化.DCD 偽指令分配的內 存不需要字對齊,一般可用來定義數據表格或其它常數.

偽指令格式:

{label} DCD expr{,expr}{,expr}…

{label} DCDU expr{,expr}{,expr}… 其中 label 內存塊起始地址標號.

expr 常數表達式或程序中的標號.內存分配字節數由 expr 個數決定. 偽指令應用舉例如下:

Vectors

LDR PC,ReserAddr

LDR PC,UndefinedAddr

ResetAddr DCD Reset

UndefinedAddr DCD Undefined

Reset

Undefined

X DCDO

DCDO 用於分配一段字內存單元.並將每個單元的內容初始化為該單元相對於靜態基址寄存器的偏移量.DCDO 偽指令作為基於靜態基址寄存器 R9 的偏移量分配內存單 元.DCDO 偽指令分配的內存需要字對齊.

偽指令格式;

{label} DCDO expr{,expr}{,expr}…

其中 label 內存塊起始地址標號.

expr 地址偏移表達式或程序中的標號.內存分配的字數由 expr 個數決定.

偽指令應用舉例如下; IMPORT externsym

DCDO externsym ;分配 32 位的字單元,其值為標號 externsym 基於 R9 的偏移

X DCFD DCFDU

DCFD 用於分配一段雙字的內存單元,並用雙精度的浮點數據 fpliteral 初始化。每 個雙精度的浮點數占據兩個字單元。DCFD 偽指令分配的內存需要字對齊。

DCFDU 具有 DCFD 同樣的功能,但分配的內存不需要字對齊。 偽指令格式:

{label} DCFD fpliteral{,fpliteral}{,fpliteral}…

{label} DCFDU fpliteral{,fpliteral}{,fpliteral}… 其中 label 內存塊起始地址標號.

fpliteral 雙精度的浮點數. 偽指令應用舉例如下;

DCFD 2E30,-3E-20

DCFDU -.1,1000,2.1E18

X DCFS DCFSU

DCFS 用於分配一段字的內存單元,並用單精度的浮點數據 fpliteral 初始化.每個 單精度的浮點數占據一個字單元.DCFD 偽指令分配的內存需要字對齊.

DCFSU 具有 DCFS 同樣的功能,但分配的內存不需要字對齊. 偽指令格式:

{label} DCFS fpliteral{,fpliteral}{,fpliteral}…

{label} DCFSU fpliteral{,fpliteral}{,fpliteral}… 其中 label 內存塊起始地址標號

fpliteral 單精度的浮點數.

偽指令應用舉例如下;

DCFS 1.1E2,-1.3E10,0.0999

X DCI

在 ARM 代碼中,DCI 用於分配一段字節的內存單元,用指定的數據 expr 初始化.指定 內存單元存放的是代碼,而不是數據.

在 Thumb 代碼中,DCI 用於分配一段半字節的內存單元,用指定的數據 expr 初始化. 指定內存單元存放的是代碼,而不是數據.

偽指令格式:

{label} DCI expr

其中 label 內存塊起始地址標號. expr 可為數字表達式.

DCI 偽指令和 DCD 偽指令非常類似,不同之處在於 DCI 分配的內存中的數據被標識 為指令.可用於通過宏指令業定義處理器不支持的指令.

偽指令應用舉例如下;

MACRO ;宏定義(定義 NEWCMN Rd,Rn 指令) NEWCMN $Rd,$Rm ;宏名為 NEWCMN,參數為 Rd 和 Rm DCI 0xe16a0e20:OR:($Rd:SHL:12):OR:$Rm

MEND

X DCQ DCQU

DCQ 用於分配一段雙字的內存單元,並用 64 位的整數數據 literal 初始化.DCQ 偽指 令分配的內存需要字對齊.

DCQU 具有 DCQ 同樣的功能,但分配的內存不需要字對齊. 偽指令格式:

{label} DCQ {-}literal{,{-}{literal}}…

{label} DCQU {-}literal{,{-}{literal}}…

其中 label 內存塊起始地址標號.

literal 64 位的數字表達式.取值范圍為 0~264-1 當literal前有“.”號 時,取值范圍為-263~-1 之間

偽指令應用舉例如下;

DCQU 1234,-76568798776

X DCW DCWU

DCW用於分配一段字的內存單元,並用指定的數據expr初始化.DCW偽指令分配的內 存需要字對齊.

DCWU 具有 DCW 同樣的功能,但分配的內存不需要字對齊. 偽指令格式:

{label} DCW expr{,expr}{,expr}…

{label} DCWU expr{,expr}{,expr}… 其中 label 內存塊起始地址標號.

expr 數字表達式,取值范圍為-32768~65535. 偽指令應用舉例如下;

DCW -592,123,6756

報告偽指令

報告偽指令用於匯編報告指示.該類偽指令如下: 斷言錯誤:ASSERT;

匯編診斷信息顯示:INFO; 設置列表選項:OPT; 插入標題:TTL 和 SUBT.

X ASSERT

ASSERT 為斷言錯誤偽指令.在匯編編譯器對匯編程序的第二遍掃描中,如果其中 ASSERT 條件不成立,ASSERT 偽指令將報告該錯誤信息.

偽指令格式:

ASSERT Logical_expr

其中 Logical_expr 用於斷言的邏輯表達式 偽指令應用舉例如下

ASSERT Top<>Temp ;斷言 Top 不等於 Temp

X INFO

匯編診斷信息顯示偽指令,在匯編器處理過程中的第一遍掃描或第一遍掃描時報告診斷信息.

偽指令格式:

INFO numeric_expr,string_expr

其中 numeric_expr 數據表達式.若值為 0,則在第一遍掃描時報告診斷信息.否則在第一遍掃描時報告診斷信息.

strint_expr 要顯示的字串 偽指令應用舉例如下:

INFO 0,”Version 0.1” ;在第二遍掃描時,報告版本信息

if cont1 > cont2 ;如果 cont1 > cont2

INFO 1,”cont1 > cont2” ;則在第一遍掃描時報告”cont1 > cont2”

X OPT

設置列表選項偽指令.通過 OPT 偽指令可以在源程序中設置列表選項. 偽指令格式:

OPI n

其中 n 所設置的選項的編碼如下:

1 設置常規列表選項

2 關閉常規列表選項

4 設置分頁符,在新的一頁開始顯示

8 將行號重新設置為 0

16 設置選項,顯示 SET,GBL,LCL 偽指令

32 設置選項,不顯示 SET,GBL,LCL 偽指令

64 設置選項,顯示宏展開

128 設置選項,不顯示宏展開

256 設置選頂,顯示宏調用

512 設置先項,不顯示宏調用

1024 設置選頂,顯示第一遍掃描列表

2048 設置選項,不顯示第一遍掃描列表

4096 設置選項目,顯示條件匯編偽指令

8192 設置選項,不顯示條件匯編偽指令

16384 設置選項,顯示 MEND 偽指令

32768 設置選項,不顯示 MEND 偽

默認情況下,-list 選項生成常規的列表文件,包括變量聲明,宏展開,條件匯編偽 指令及MEND偽指令,而且列表文件只是在第二遍掃描時給出,通過OPT偽指令,可以在源 程序中改變默認的選項.

偽指令應用舉例如下

;代碼

OPT

512

;不顯示宏調用

;代碼

X TTL SUBT

TTL 和 SUBT 為插入標題偽指令.

TTL 偽指令在列表文件的每一頁的開頭插入一個標題.該 TTL 偽指令的作用在其后 的每一頁,直到遇到新的 TTL 偽指令.

SUBT 偽指令在列表文件的每頁的開頭第一個子標題.該 SUBT 偽指令的作用在其后的每一頁,直到遇到新的 SUBT 偽指令.

偽指令格式: TTL title SUBT subtitle

其中 title 標題名.

subtitle 子標題名. 偽指令應用舉例如下;

TTL mainc

SUBT subc con

匯編控制偽指令

匯編控制偽指令用於條件匯編,宏定義,重復匯編控制等.該類偽指令如下: 條件匯編控制: IF,ELSE 和 ENDIF

宏定義: MACRO 和 MEND 重復匯編: WHILE 及 WEND

X IFELSE ENDIF

IF ,ELSE 和 ENDIF 偽指令能夠根據條件把一段代碼包括在匯編程序內或將其排除 在程序之外.

[與 IF 同義,|與 ELSE 同義,]與 ENDIF 同義 偽指令格式:

IF logical_expr

;指令或偽指令代碼段 1

{

ELSE

}

;指令或偽指令代碼段 2

ENDIF

其中 logical_expr 用於控制的邏輯表達式.若條件成立,則代碼段落在匯編 源程序中有效.若條件不成立,代碼段 1 無效,同時若使用 ELSE 偽指令,代碼段有效.

偽指令應用舉例如下;

IF {CONFIG}=16

BNE

rt_udiv_1

LDR R0,= rt_div0

BX R0

ELSE

BEQ

ENDIF

rt_div0

IF,ELSE 和 ENDIF 偽指令是可以嵌套使用的.

X MACRO MEND

MACRO 和 MEND 偽指令用於宏定義.MACRO 標識宏定義的開始,MEND 標識宏定義久的 結束.用MACRO及MEND定義的一段代碼,稱為宏定義體.這樣在程序中就可以通過宏指令多次調用該代碼段.

偽指令格式: MACRO

{$label} macroname {$parameter} {$parameter}…

;宏定義體.

MEND

其中 $label 宏指令被展開時,label 可被替換成相應的符號,通常為一 個標號在一個符號前使用$表示被匯編時將使用相應的值替代$后的符號.

macroname 所定義的宏的名稱.

$parameter 宏指令的參數.當宏指令被展開時將被替換成相應的值,類

似於函數中的形式參數

對於子程序代碼比較短,而需要傳遞的參數比較多的情況下可以使用匯編技術.首 先要用 MACR 和 MEND 偽指令定義宏,包括宏定義體代碼.在 MACRO 偽指令之后的第一行聲明宏的原型,其中包含該宏定義的名稱,及需要的參數.在匯編程序中可以通過該宏定義 的名稱來調用它.當源程序被匯編時,匯編編譯器將展開每個宏調用,用宏定義體代替源 程序中的宏定義的名稱,並用實際的參數值代替宏定義時的形式參數.

偽指令應用舉例如下 MACRO

CSI_SETB ;宏名為 CSI_SETB,無參數

LDR

R0,=rPDATG

;讀取 GPG0 口的值

LDR

R1,[R0]

ORR

R1,R1#0x01

;CSI 置位操作

STR

R1,[R0]

;輸出控制

MEND

帶參數的宏定義如程序清單: MACRO

$IRQ_Label HANDLER $IRQ_Exception

EXPORT $IRQ_Label

IMPORT $IRQ_Exception

$IRQ_Label

SUB LR,LR,#4

STMFD SP!,{R0-R3,R12,LR} MRS R3,STSR

STMFD SP!,{R3}

MEND

X WHIL WEND

WHILE 和 WEND 偽指令用於根據條件重復匯編相同的或幾乎相同的一段源程序.

偽指令格式:

WHILE logical_expr

;指令或偽指令代碼段

WEND

其中 logical_expr 用於控制的邏輯表達式.若條件成立,則代碼段在匯編 源程序中有效,並不斷重復這段代碼直到條件不成立.

偽指令應用舉例如下;

WHILE no<5

no SETA no+1

… WEND

WHILE 和 WEND 偽指令是可以嵌套使用的.

雜項偽指令

雜項偽指令在匯編編程設計較為常用,如段定義偽指令,入口點設置偽指令,包 含文件偽指令,標號導出或引入聲明等,該類偽指令如下;

邊界對齊: ALIGN 段定義: AREA

指令集定義: CODE16 和 CODE32 匯編結束: END

程序入口: ENTRY 常量定義: EQU 聲明一個符號可以被其它文件引用:EXPORT 和 GLORBAL 聲明一個外部符號:IMPORT 和 EXTERN

包含文件:GET 和 INCLUDE 包含不被匯編的文件:INCBIN 保留符號表中的局部符號:KEEP 禁止浮點指令:NOFP 指示兩段之間的依賴關系:REQUIRE

堆棧 8 字節對准:PEQUIRE8 和 PRESERVE8

給特定的寄存器命名:RN 標記局部標號使用范圍的界限:ROUT.

X ALIGN

ALIGN 偽指令通過添加補丁字節使當前位置滿足一定的對齊方式. 偽指令格式:

ALIGN {expr{,offset}}

其中 expr 數字表達式,用於指定對齊的方式.取值為2的n 次冪,如 1,2,4,8, 等,不能為 0 其沒有 expr.,則默認為字對齊方式.

offset 數字表達式,當前位置對齊到下面形式的地址處:offset+n*expr

在下面的情況中,需要特定的地址對齊方式;

1.Thumb 偽指令 ADR 要求地址是字對齊的.而 Thumb 代碼中地址標號可能不是字對 齊的.這時就要使用偽指令 ALIGN4 使 Thumb 代碼中地址標號為字對齊.

2.由於有些 ARM 處理器的 Cache 采用了其他對齊方式.如 16 字節對齊方式,這時使用 ALIGN 偽指令指定合適的對齊方式可以充分發揮 Cache 的性能優勢.

3.LDRD 和 STRD 指令要求存儲單元為 8 字節對齊.這樣在為 LDRD/STRD 指令分配的 存儲單元前要使用偽指令 ALIGN8 實現 8 字節對齊方式.

4.地址標號通常自身沒有對齊要求,而在 ARM 代碼中要求地起標號對齊是字對齊 的,Thumb 代碼中要求半字對齊.這樣可以使用 ALIGN4 和 ALIGN2 偽指令來調整對齊方

式.

偽指令應用舉例如下:

通過 ALIGN 偽指令使程序中的地址標號字對齊:

AREA Example ,CODE,READONLY ;聲明代碼段 Example

START LDR R0,=Sdfjk

MOV PC,LR

Sdfjk DCB 0x58 ;定義一字節存儲空間,字對齊方式被破壞 ALIGN ;聲明字對齊

SUBI MOV R1,R3 ;其它代碼

MOV PC ,LR

在段定義 AREA 中,也可使用 ALIGN 偽指令對齊,但表達式的數字含義是同的 AREA MyStack,DATA,NOINIT,ALIGN=2 ;聲明數據段

;MyStack,並重新字對齊

IrqStackSpace

SPACE

IRQ_STACK_LEGTH*4

;中斷模式堆棧空間

FiqStackSpace

SPACE

FIQ_STACK_LEGTH*4

;快速中斷模式堆棧空間

AbtStackSpace

SPACE

ABT_STACK_LEGTH*4

;中止義模式堆棧空間

UndtStackSpace

SPACE

UND_STACK_LEGTH*4

;未定義模式堆棧

將兩個字節的數據放在同一個字的第一個字節和第四個字節中,帶 offset 的 ALIGN

對齊:

AREA

offsetFxample,

CODE

DCB

0x31

;第一個字節保存 0x31

ALIGN

4,3

;字對齊

DCB

0x32

;第四個字節保存 0x32

X AREA

AREA 偽指令用於定義一個代碼段或數據段.ARM 匯編程序設計采用分段式設計,一 個 ARM 源程序至少需要一個代碼段,大的程序可以包含多少個代碼段及數據段.

偽指令格式:

AREA sectionname{,attr}{,attr}…

其中 sectionname 所定義的代碼段或數據段的名稱.如果該名稱是以數據開頭 的,則該名稱必須用“|”括起來,如|1_datasec|.還有一些代 碼段具有的約定的名稱.如|text|表示 C 語言編譯器產生的代碼段或者與 C 語言庫相關的代碼段.

attr 該代碼段或數據段的屬性.

在 AREA 偽指令中,各屬性之間用逗號隔開.以下為段屬性及相關說明:

ALIGN = expr.默認的情況下,ELF 的代碼段和數據段是 4 字節對齊的,expr 可以 取 0~31 的數值,相應的對齊方為 2expr 字節對齊.如 expr=3 時為字節對齊.對於代碼段,expr 不能為0或 1;

ASSOC = section.指定與本段相關的 ELF 段.任何時候連接 section 段也必須包括

sectionname 段;

DODE 為定義代碼段.默認屬性為 READONLY;

COMDEF 定義一個通用的段.該段可以包含代碼或者數據.在其它源文件中,同名的 COMDEF 段必須相同;

COMMON 定義一個通用的段.該段不包含任何用戶代碼和數據,連接器將其初始化為 此.各源文件中同名的 COMMON 段共用同樣的內存單元,連接器為其分配合適的尺寸;

DATA 為定義段.默認屬性為 READWRITE;

NOINIT 指定本數據段僅僅保留了內存單元,而沒有將各初始寫入內存單元,或者將 內存單元值初始化為 0;

READONLY 指定本段為只讀,代碼段的默認屬性為 READONLY; READWRITE 指定本段為可讀可寫.數據段的默認屬性為 READWRITE; 使用AREA偽指令將程序分為多個ELF格式的段,段名稱可以相同, 這時同名的段被

放在同一個 ELF 段中. 偽指令應用舉例如下;

AREA Example ,CODE,READNOLY ;聲明一個代碼,名為 Example

X CODE16 CODE32

CODE16 偽指令指示匯編編譯器后面的指令為 16 位的 Thumb 指令. CODE32 偽指令指示匯編編譯器后面的指令為 32 位的 ARM 指令. 偽指令格式:

CODE16

CODE32

CODE16 和 CODE32 偽指令只是指示匯編編譯器后面的指令的類型,偽指令本身並不 進行程序狀態的切換.要進行狀態切換,可以使用 BX 指令操作.

偽指令應用舉例如下;

AREA Example CODE,READONLY CODE32

使用 CODE16 和 CODE32 定義 Thumb 指令及 ARM 指令並用 BX 指令進行切換。 CODE16 和 CODE32 的使用:

AREA ArmThumC,CODE,READONLY CODE32

ADR R0,ThumbStart+1

BX R0

CODE16

ThumbStart

MOV R0,#10

… END

X END

END 偽指令用於指示匯編編譯器源文件已結束.每一個匯編源文件均要使用一個 END 偽指令,指示本源程序結束

偽指令格式: END

X ENTRY

ENTRY 偽指令用於指定程序的入口點. 偽指令格式:

ENTRY

一個程序(可以包含多個源文件)中至少要有一個 ENTRY,可以有多個 ENTRY.但一個源文件中最多只有一個 ENTRY.

偽指令應用舉例如下.

AREA, Example, CODE,READNOLY ENTRY

CODE32

START MOV R1,#0x5F

X EQU

EQU 偽指令為數字常量,基於寄存器的值和程序中的標號定義一個名稱。*與 EQU 同義。

指令格式:

name

EQU

expr{,type}

其中

name

要定義的常量的名稱.

expr

基於寄存器的地址值,程序中的標號,32 位地址常量或 32 位常量.

type

當 expr 為 32 位常量時,可用 type 指示 expr 表示的數據類型.如下

CODE16

CODE32

DATA

EQU 偽指令的作用類似於 C 語言中的#define.用於為一個常量定義名稱. 偽指令應用舉例如下;

T_bit

EQU

0x20

;定義常量 T_bit,其值為 0x20

PLLCON

EQU

0xE01FC080

;定義寄存器 PLLCON,地址為 0Xe01F080

ABCD

EQU

label+8

;定義 ABCD 為 label+8

X EXPORT GLOBAL

EXPORT 聲明一個符號可以被其它文件引用.相當於聲明了一個全局變量. GLOBAL 與 EXPORT 相同

指令格式:

EXPORT symbol{[WEAK]}

GLOBAL symbol{[WEAK]}

其中 symbol 要聲明的符號名稱

[WEAK] 聲明其它的同名符優先於本符號被引用. 偽指令應用舉例如下:

EXPORT InitStack

GLOBAL Vectors

X IMPORT EXTERN

IMJPORT 偽指令指示編譯器當前的符號不是在本源文件中定義的,而是在其他源文 件中定義的,在本源文件中可能引用該符號.

EXTERN 與 IMPORT 相同 指令格式:

IMPORT symbol{[WEAK]} EXTERN symbol{[WEAK]}

其中 symbol 要聲明的符號名稱.

[WEAK] 指定該選項后,如果 symbol 在所有的源程序中都沒有被定義,編 譯器也不會生任何錯誤信息,同時編譯器也不會到當前沒有被 INCLUDE 進來庫中去查找該標號.

使用 IMPORT 或 EXTERN 聲明外部標號時,若連接器在連接處理時不能解釋該符號, 而偽指令中沒有[WEAK]選項,則連接器會報告錯誤,若偽指令中有[WEAK]選項,則連接器 不會報告錯誤,而是進行下面的操作:

1.如果該符號被 B 或者 BL 指令引用,則該符號被設置成下一條指令的地址,該 B 或 者 BL 指令相當於一條 NOP 指令.

2.其它情況下該符號被設置 0 偽指令應用舉例如下

IMPORT InitStack

EXTERN Vectors

X GET INCLUDE

GET 偽指令將一個源文件包含到當前源文件中,並將被包含的文件在具當前位置進 行匯編處理 INCLUDE 與 GFT 同義

指令格式

GET filename

INCLUDE filename

其中 filename 要包含的源文件名,可以使用路徑信息.

GET 偽指令通常用於包含一些宏定義或常量定義的源文件.如用 EQU 定義的常量,用 MAP 和 FIELD 定義的結構化的數據類型,這樣的源文件類似於 C 語言中的頭文 件,GET,INCLUDE 偽指令不能用來包含目標文件,而 INCBIN 偽指令可以包含目標文件.

偽指令應用舉例如下 INCLUDE LPC2106.inc

X INCBIN

INCBIN 偽指令將一個文件包含到當前源文件中,而被包含的文件不進行匯編處理. 指令格式:

INCBIN filename

其中 filename 要包含的源文件名,可以使用路徑信息.

通常可以使用 INCBIN 將一個執行文件或者任意數據包含到當前文件中,被包含的 執行文件或數據將被原封不動地放下當前文件中,編譯器從 INCBIN 偽指令后面開始繼續處理.

偽指令應用舉例如下 INCBIN charlib.bin

X KEEP

KEEP 偽指令指示編譯器保留符號表中的局部符號. 偽指令格式

KEEP {symbol}

其中 symbol 要保留的局部標號.若沒有此項,則除了基於寄存器處的所有符 號將包含在目標文件的符號表中.

X NOFP

NOFP 偽指令用於禁止源程序中包含浮點運算指令. 偽指令格式.

NOFP

X REQUIRE

REQUIRE 偽指令指定段之間的依賴關系. 偽指令格式

REQUIRE label

其中 label 所需要的標號的名稱.

當進行鏈接處理時,包含了 REQUIRE label 偽指令的源文件,則定義 label 的源文 件也被包含.

X PEQUIRE8 PRESERVE8

PEQUIRE8 偽指令指示當前文件請求堆棧為 8 字節對齊, PRESERVE8 偽指令指示當前文件保持堆棧為 8 字節對齊. 偽指令格式.

PEQUIRE8

PRESERVE8

鏈接器保證要求 8 字節對齊的堆棧只能被堆棧為 8 字的對齊的代碼調用.

X RN

RN 偽指令用於給一個特殊的寄存器命名.

偽指令格式

name RN expr

其中 name 給寄存器定義的名稱. expr 寄存器編號

偽指令應用舉例如下

COUNT RN 6 ;定義寄存器 R6 為 COUT Count1 RN R7 ;定義寄存器 R7 為 Cout1

X ROUT

ROUT 偽指令用於定義局部標號的有效范圍. 偽指令格式如下.

{name} ROUT

其中 name 所定義的作用范圍的名稱.

當沒有使用 ROUT 偽指令時,局部標號的作用范圍為其所在段.ROUT 偽指令的作用范 圍在本 ROUT 偽指令和下一個 ROUT 偽指令之間(指同一段中的 ROUT 偽指令.)

偽指令應用舉例如下.

routineA ROUT ;定義局部標號的有效范圍,名稱為 routineA

3routineA ;routineA 范圍內的局部標號 3

BEQ %4routineA ;若條件成立,跳轉到 routineA 范圍內的局部標號 4

BEG %3 ;若條件成立,跳轉到 routineA 范圍內的局部標號 3

4routineA … ;routineA 范圍內的局部標號 4

otherstuff ROUT ;定義新的局部標號的有效范圍

ARM 偽指令

ARM 偽指令有 ADR,ADRL,LDR,NOP,LDFD,LDFS.

X ADR

為小范圍的地址讀取偽指令.ADR 指令將基於 PC 相對偏移的地址值或基於寄存器相對偏移的地址值讀取到寄存器中,當地址值是非字對齊時,取值范圍-255~255 字節之間, 當地址值是字對齊時,取值范圍-1020~1020 字節之間

X ADRL

為中等范圍的地址讀取偽指令.ADRL 指令將基於 PC 相對偏移的地址值或基於寄存 器相對偏移的地址值讀取到寄存器中,當地址值是非字對齊時,取值范圍-64K~64K 字節 之間,當地址值是字對齊時,取值范圍-256K~256K 字節之間

X LDR

為大范圍的地址讀取偽指令.LDR 偽指令用於加載 32 位的立即數或一個地址值到指 定寄存器.若匯編器將常量放入文字池,並使用一條程序相對偏移的 LDR 指令從文字池 讀出常量,則從 PC 到文字池的偏移量必須小於 4KB.

X NOP

為空操作偽指令.NOP 偽指令在匯編時將會被代替成 ARM 中的空操作,比如可能為 MOV R0,R0 指令等.

X LDFD

偽指令將一個雙精度浮點數常數放進一個浮點數寄存器. 偽指令格式:

LDFD fx,=expr

其中 fx 浮點數寄存器

expr 雙精度浮點數值. 偽指令應用舉例如下

LDFD f1,=0.12

X LDFS

偽指令將一個單精度浮點數常數放進一個浮點寄存器. 偽指令格式:

LDFS fx,=expr

其中 fx 浮點數寄存器

expr 單精度浮點數值. 偽指令應用舉例如下

LDFS f1,=O.12

Thumb 偽指令

Thumb 偽指令有 ADR,LDR,NOP.

X ADR

為小范圍的地址讀取偽指令.ADR 指令將基於 PC 相對偏移的地址值讀取到寄存器中, 偏移量必須是正數並小於 1KB.

X LDR

為大范圍的地址讀取偽指令.LDR 偽指令用於加載 32 位的立即數或一個地址值到指定寄存器.

若匯編器將常量放入文字池,並使用一條程序相對偏移的 LDR 指令從文字池讀出常 量,則從 PC 到文字池的偏移量必須是正數並小於 1KB

X NOP

為空操作偽指令.NOP 偽指令在匯編時將會被代替成 ARM 中的空操作,比如可能為 MOV R8,R8 指令等.

ARM 匯編程序設計

文件格式

ARM 源程序文件(即源文件)為文件格式,可以使用任一文本編輯器編寫程序代碼. 一般地,ARM 源程序文件名的后綴名如下表:

程序

文件名

匯編

*.S

引入文件

*.INC

C 程序

*.C

頭文件

*.H

在一個項目中,至少要有一個匯編源文件或 C 程序文件,可以有多個匯編源文件或

多個 C 程序文件,或者 C 程序文件和匯編文件兩者的組合.

ARM 匯編的一些規范

匯編語句格式

ARM 匯編中,所有標號必須在一行的頂格書寫,其后面不要添加“:”,而所有指令均 不能頂格書寫。ARM 匯編器對標識符大小寫敏感,書寫標號及指令時字母大小寫要一致, 在 ARM 匯編程序中,一個 ARM 指令、偽指令、寄存器名可以全部為大寫字母,也可以全 部為小寫字母,但不要大小寫混合使用。注釋使用“;”,注釋內容由“;”開始到此行 結束,注釋可以在一行的頂格書寫。

格式:[標號] <指令|條件|S> <操作數>[;注釋] 源程序中允許有空行,適當地插入空行可以提高源代碼的可讀性。如果單行太長,

可以使用字符“\”將其分行,“\”后不能有任何字符,包括空格和制表符等。對於變

量的設置,常量的定義,其標識符必須在一行的頂格書寫。 匯編指令正確的例子和錯誤的例子如下:

正確的例子:

Str1

SETS

My

string1.”

;設置字符串變量 Str1

Count

RN

R0

;定義寄存器名 Count

USR_STACK

EQU

64

;定義常量

START LDR R0,=0x1123456 ;R0=0x123456H

MOV R1,#0

LOOP

… 錯誤的例子:

MOV R2,#3

START MOV R0,#1 ;標號 START 沒有頂格寫

ABC: MOV R1,#2 ;標號后不能帶:

MOV R2,#3 ;命令不允許頂格書寫

loop Mov R2,#3 ;指令中大小寫混合

B Loop ;無法跳轉到 Loop 標號

標號

在 ARM 匯編中,標號代表一個地址,段內標號的地址在匯編時確定,而段外標號的 地址值在連接時確定。根據標號的生成方式,可以有以下 3 鍾:

X 基於 PC 的標號

基於 PC 的標號時位於目標指令前的標號或程序中的數據定義偽指令前的標號,這種標號在匯編時將被處理成 PC 值加上或減去一個數字常量。它常用於表示跳轉指令的

目標地址,或者代碼段中所嵌入的少量數據。

X 基於寄存器的標號

基於寄存器的標號通常用 MAP 和 FILED 偽指令定義,也可以用於 EQU 偽指令定義,這種標號在匯編時被處理成寄存器的值加上或減去一個數字常量。它常用於訪問位於數據段中的數據。

X 絕對地址

絕對地址是一個 32 為的數字量,它可以尋址的范圍為 0~232-1,可以直接尋址整 個內存空間。

局部標號

局部標號主要用於局部范圍代碼中,在宏定義也是很有用的。局部標號是一個 0~

99 之間的十進制數字,可重復定義,局部標號后面可以緊接一個通常表示該局部變量作用范圍的符號。局部變量的作用范圍為當前段,也可以用偽指令 ROUT 來定義局部標 號的作用范圍。

局部標號定義格式:N{routname}

其中:N 局部標號,為 0~99

routname 局部標號作用范圍的名稱,由 ROUT 偽指令定義 局部標號引用格式:

%{F|B}{A|T} N{routname}

其中:

%

表示局部標號引用操作

F

指示編譯器只向前搜索

B

指示編譯器只向后搜索

A

指示編譯器搜索宏的所有嵌套層次

T

指示編譯器搜索宏的當前層

如果F和B 都沒有指定,則編譯器先向前搜索,再向后搜索。如果A和T 都沒有指 定,編譯器搜索所有從宏的當前層次到宏的最高層次,比當前層次的層次不再搜索。

如果指定了 routname,編譯器向前搜索最近的 ROUT 偽指令,若 routname 與該 ROUT

偽指令定義的名稱不匹配,編譯器報告錯誤,匯編失敗。 示例如下:

routintA ROUT

3routineA

4routineA

BEQ %4routineA BGE %3

otherstuff ROUT

符號

在 ARM 匯編中,符號可以代表地址、變量、數字常量。當符號代表地址時又稱為標號,符號就是變量的變量名、數字常量的名稱、標號,符號的命名規則如下:

1、符號由大小寫字母、數字以及下划線組成;

2、除局部標號以數字開頭外,其它的符號不能以數字開頭;

3、符號區分大小寫,且所有字符都是有意義的;

4、符號在其作用域范圍你必須是唯一的;

5、符號不能與系統內部或系統預定義的符號同名;

6、符號不要與指令助記符、偽指令同名。

常量

X 數字常數

數字常量有三種表示方式: 十進制數,如:12,5,876,0; 十六進制數,如 0x4387,0xFF0, 0x1;

n 進制數,用 n-XXX 表示,其中 n 為 2~9,XXX 為具體的數。如 2-010111,8-4363156

等。

X 字符常量

字符常量由一對單引號及中間字符串表示,標准 C 語言中的轉義符也可使用。如果 需要包含雙引號或“$”,必須使用“”和$$代替。如下:

Hello SETS “Hello World!”

Errorl SETS “The parameter ““VFH””error$$2”

X 布爾常量

布爾常量的邏輯真為{TRUE},邏輯假為{FALSE}.如下:

testno SETS {FALSE}

段定義

ARM 匯編程序設計采用分段式設計,一個 ARM 源程序至少需要一個代碼段,大的程序 可以包含多個代碼段及數據段.

ARM 匯編程序經過匯編處理后生成一個可執行的映象文件,該文件通常包含下面 3 部分內容:

* 一個或多代碼段.代碼段通常是只讀的.

* 零個或多個包含初始化值的數據段.這些數據段通常是可讀寫的. 零個或多個不包含初始值的數據段.這些數據被初始化為 0,通常中可讀寫的. 連接器根據一定的規則將各個段安排到內存中的相應位置.源程序中段之間的相鄰

關系與執行的映象文件中段之間的相鄰關系並不一定相同. 代碼段的例子如下:

AREA Hello,CODE,READONLY ;聲明代碼段 Hello

ENTRY ;程序入口(調試用) START MOV R7,#10

MOV R6,#5

ADD

R6,R6,R7

;R6=R6+R7

B

;死循環

END

每一個匯編文件都要以 END 結束,包括*INC 文件,否則編譯會有警告. 數據段的例子如下:

AREA DataArea,DATA,NOINIT,ALLGN=2

DISPBUF SPACE 100

RCVBUF SPACE 100

宏定義及其作用

使用宏定義可以提高程序的可讀性,簡化程序代碼和同步修改.ARM 宏定義與標准 C 的#define 相似,只在源程序中進行字符代換.宏定義從 MACRO 偽指令開始,到 MEND 結束, 並可以使用參數.

宏要先定義,然后再使用.使用時直接書寫宏名,並根據對應的宏定義格式設置輸入 參數或書寫標號等.當源程序被匯編時,匯編編譯器將展開每一個宏調用,用宏定義體代 替程序中的宏調用,並使用實際的參數值代替宏定義時的形式參數.

程序程序清單見后,程序中定義了一個宏 CALL,用於調用子程序,調用時設置所要 調用的子程序名$Function 及兩個入口參數$dat1 和$dat2.由於宏定義體中使用的是 MOV 指令,所以$dat1 參數只能為 8 位圖的立即數或通用寄存器.

宏應用的例子:

MACRO

;宏定義

CALL

$Function,$dat1,$dat2

;宏名稱為 CALL,帶 3 個參數

IMPORT

$Function

;聲明外部子程序

MOV

R0,$dat1

;設置子程序參數,R0=$dat1

MOV

R1,$dat2

BL

Function

;調用子程序

MEND ;宏定義結束

CALL FADD1,#3,#2 ;宏調用

… 匯編預處理后,宏調用將被展開,程序清單如下:

IMPORT FADD1

MOV R0,#3

MOV R1,#3

BL FADD1

子程序的調用

使用 BL 指令進行調用,該指令會把返回的 PC 值保存在 LR,示例如下:

BL DLEAY

… DELAY …

MOV PC,LR

當子程序執行完畢后,使用 MOV,B/BX,STMFD 等指令返回,當然 STMFD 要與 LDMFD 配 套使用,子程序返回的方法:

MOV PC,LR 或 B LR

或 BX LR

或 STMFD SP!{R0-R7,PC }

ARM7TDMI(-S)是沒有BLX指令的,但是可以通過幾條程序實現其功能,模擬BLX指令如下:

ADR

R1,DELAY+1

MOV

LR,PC

;保存返回地址到 LR

BX

R1

;跳轉並切換指令集

數據比較跳轉

匯編程序可以使用CMP指令進行兩個數據比較,然后調高相應的ARM條件碼,實現跳 轉.代碼例子如下:

CMP

R5,#10

BEQ

DOEQUAL

;若 R5 為 10,則跳轉到 DOEQUAL

CMP

R1,R2

ADDHI

R1,R1,#10

;若 R1>R2,則 R1=R1+10

ADDLS

R1,R1,#5

;若 R1<=R2,則 R1=R1+5

ANDS

R1,R1,#0x80

;R1=R1&0x80,並設置相應標志位

循環

BNE

WAIT

;若 R1 的 d7 位為則跳轉到 WAIT

下面的代碼為循環程序的例子.例子指定循環次數,每循環一次進行減 1 操作,並判

斷結果是否為 0,若為 0 則退出循環.

MOV

R1,#10

LOOP

;循環體

SUBS

R1,R1,#1

BNE

LOOP

數據塊復制

程序可以使用存儲器訪問指令 LDM/STM 指令進行讀取和存儲,數據塊復制示例如 下:

LDR R0,=DATA_DST ;指向數據目標地址

LDR

R1,=DATA_SRC

;指向數據源地址

MOV

R10,#10

;復制數據個數為 10*N 個字

LOOP

LDMIA

R1!,{R2-R9}

;N 為 LDM/STM 指令操作數據個數

STMIA

R0!,{R2-R9}

SUBS

R10,R10,#1

BNE

LOOP

棧操作

ARM 使用存儲器訪問指令 LDM/STM 實現棧操作,用於子程序寄存器保存.注意,使用堆棧時,要先分配好堆棧空間,設置好寄存器 R13(即堆棧指針 SP),否則操作失敗.

OUTDAT

STMFD SP!{R0-R7,LR}

BL DELAY

LDMFD SP!{R0-R7,PC}

特殊寄存器定義及應用

基於 ARM 核的芯片一般有片內外設,它們通過其特殊寄存器訪問.片內外設的使用 示例如下:

WDTC

EQU

0xE000000

;寄存器定義

LDR

R0,=WDTC

MOV

R1,#0x12

STR

R1,[R0]

;WDTC=0x12

散轉功能

散轉是匯編程序常用的一種算法,其示例如下:

CMP R0,#MAXINDEX ;判斷索引號是否超出最大索引值 ADDLO PC,PC,R0,LSL #2 ;若沒有超出,則跳轉到相應位置 B ERROR ;若已經超出,則進行出錯處理

;散轉表,對應索引號為 0~N B FUN1

B FUN2

B FUN3

查表操作

查表操作是匯編程序常用的一種操作,其示例如下:

LDR

LDR

R3,=DISP_TAB ;取得表頭

R2,[R3,R5,LSL #2] ;根據 R5 的值查表,取出相應的值

DISR_TAB

DCD DCD DCD

0xC0,0xF9,0xA4,0x99,0x92

0x82,0xF8,0x80,0x90,0x88,0x83

0xC6,0xa1,0x86,0x8E,0xFF

長跳轉

;下表為 0--F 的字模

ARM 的 B 和 BL 指令不能全空間跳轉,但通過對 PC 進行賦值,實現 32 位地址的跳轉/

調用,示例如下:

ADD LR,PC,#4 ;保存返回地址,即 RET_FUN LDR PC,[PC,#-4] ;跳轉到 LADR_FUN

DCD LADR_FUN

RET_FUN …

也可使用偽指令 LDR PC,=LADR_FUN 實現長跳轉。

對信號量的支持

ARM 提供一條內存與寄存器交換的指令 SWP 用於支持信號量的操作,實現系統任務 之間的同步或互斥,其使用的例子如下:

DISP_SEM EQU 0x40002A00

DISP_WAIT MOV

R1,#0

LDR

R0,=DISP_SEM

SWP

R1,R1[R0]

;取出信號量,並設置其為 0

CMP

R1,#0

;判斷是否有信號

BEQ

DISP_WAIT

;若沒有信號,則等待

偽指令使用

LDR 偽指令和 NOP 偽指令應用例子代碼如下:

LDR

R1,=0x12345678

;加載 32 位立即數

LDR

R0,=LDE_TAB

;加載標號地址

NOP

;空指令

B

;死循環

一個完整的例子

下面是匯編程序完整的例子: ABC EQU 0x12

;聲明一個代碼段 Example

AREA Example,CODE,READONLY ENIRY

CODE32

ADR R0,Thumb_START+1 ;裝載地址,並設置 d0 位為 1

BX R0 ;切換到 Thumb 狀態 CODE16 ;聲明 16 位代碼(Thumb)

Thumb_START

MOV R1,#ABC

ADD R1,R1,#0x10

B Thumb_START END

外圍部件控制

在 32 位的 ARM 核芯片中,其外圍部件的控制寄存器中,一般會設置“置位/復位”寄 存器,這樣可以方便的實現位操作,而不會影響其它位,如 IOSET=0x01 只會將 P0.1 的置 位,而其它 I/O 狀態不變,另外,ARM 存儲/保存指令具有前偏移功能,所以對外圍部件的 控制寄存器進行操作時可使用此功能,避免了每次都加載寄存器地址的操作示例如下:

LDR

R0,=GPIO_BASE

MOV

R1,#0x00

STR

R1,[R0,#0x04]

;IOSET=0x00

MOV

R1,#0x10

STR

R1,[R0,#0x0C]

;IOCLR=0x101

三級流水線介紹

ARM7TDM(-S)使用三級流水線執行指令,第一階段從內存中取回的指令,第二階段開始解碼,而第三階段實際執行指令.故此,程序計數器總是超出當前執行的指令兩條指 令.(在為跳轉指令計算偏移量時必須計算在內).因為有這個流水線,在跳轉時丟失 2 個 指令周期(因為要重新添滿流水線).所以最好利用條件執行指令來避免浪費周期.

條件跳轉示例:

CMP R0,#0

BEQ LOOP1

MOV R1,#0x10

MOV R2,#0x88

LOOP1

可以寫為更有效的:

CMP R0,#0

MOVNE R1,#0x10

MOVNE R2,#0x88

C 與匯編混合編程

在需要 C 與匯編混合編程時,若匯編代碼較結,則可使用直接內嵌匯編的方法混合 編程;否則,可以將匯編文件以文件的形式加入項目中,通過 ATPCS 規定與 C 程序相互調用及訪問.

ATPCS,即 ARM,Thumb 過程調用標准(ARM/Thumb Procedure Call Standard),它規定 了一些子程序間調用的基本規則,如子程序調用過程中的寄存器的使用規則,堆棧的使 用規則,參數的傳遞規則等.

內嵌匯編

在 C 程序嵌入匯編程序,可以實現一些高級語言沒有的功能,提高程序執行效 率.armcc 編譯器的內嵌匯編器支持,ARM 指令集,tcc 編譯器的內嵌匯編支持 Thumb 指令 集.

內嵌匯編的語法:

asm

{

指令[;指令] /*注釋*/

… [指令]

}

嵌入匯編程序的例子如下所示,其中 enable_IRQ 函數為使能 IRQ 中斷,而

disable_IRQ 函數為關閉 IRQ 中斷. 使能/禁能 IRQ 中斷:

inline void enable_IRQ(void)

{

int tmp

_asm //嵌入匯編代碼

{

MRS tmp,CPSR //讀取 CPSR 的值

BIC tmp,tmp,#0x80 //將 IRQ 中斷禁止位 I 清零,即允許 IRQ 中斷 MSR

CPSR_c,tmp //設置 CPSR 的值

}

}

inline void disable_IRQ(void)

{

int tmp;

_asm

{

MRS tmp,CPSR

ORR tmp,tmp,#0x80

MSR CPSR_c,tmp

}

}

另外一個嵌入匯編程序的例子如下所示,其中 my_strcpy 函數是字符串復制函

數,src 為源字符串指針,dst 為目標字符串指針。

制操作全部由嵌入的匯編代碼實現.在主程序中,可以使用 my_strcpy(a,b)來調用 函數,還可以使用嵌入匯編方法進行調用,嵌入匯編的代碼先要設置入口參數 R0,R1,然 后使用 BL my_strcpy ,{R0,R1}指令調用函數,其中,輸入寄存器列表為{R0,R1},沒有輸 出寄存器列表.

字符串復制:

#include <stdio.h>

void my_strcpy(const char*src, char*dst)

{

int ch;

_asm

{

loop:

#ifndef_thumb

//ARM 指令版本 LDRB ch,[src],#1

STRB ch,[dst],#1

#else

//Thumb 指令版本 LDRB ch,[src] ADD src,#1

STRB ch,[dst] ADD dst,#1

#endif

CMP ch,#0

BNE loop

}

}

int main(void)

{

const char*a=“Hello world!”

char b[20]

//my_strcpy(a,b);

_asm

{

MOV R0,a //設置入口參數 MOV R1,b

BL my_strcpy,{R0,R1} //調用 my_strcpy()函數

}

printf(“Original string:’%s’\n,”a); //顯示 my_strcpy()函數字符串復制結果

printf(“Copied string:’%s’\n,”b);

return(0);

}

內嵌匯編的指令用法

操作數.內嵌的匯編指令中作為操作數的寄存器和常量可以是表達式.這些表達式 可以是 char,short 或 int 類型,而且這些表達式都是作為無符號數進行操作.若需要帶 符號數,用戶需要自己處理與符號有關的操作.編譯器將會計算這些表達式的值,並為其 分配寄存器.

物理寄存器.內嵌匯編中使用物理寄存器有以下限制;

* 不能直接向 PC 寄存器賦值,程序跳轉只能使用B或 BL 指令實現

* 使用物理寄存器的指令中,不要使用過於復雜的C表達式.因為表達式過於復雜 時,將會需要較多的物理寄存器.這些寄存器可能與指令中的物理寄存器使用 沖突.

* 編譯器可能會使用 R12 或 R13 存放編譯的中間結果,在計算表達式的值時可能 會將寄存器 R0~R3,R12 和 R14 用於子程序調用.因此在內嵌的匯編指令中,不要 將這些寄存器同時指定為指令中的物理寄存器.

* 通常內嵌的匯編指令中不要指定物理寄存器,因為這可能會影響編譯器分配寄

存器,進而影響代碼的效率.

常量.在內嵌匯編指令中,常量前面的”#”可以省略. 指令展開.內嵌匯編指令中,如果包含常量操作數,該指令有可能被內嵌匯編器展

開成幾條指令.

標號.C 程序中的標號可以被內嵌的匯編指令使用,但是只有指令 B 可以使用 C 程序 中的標號,而指令 BL 則不能使用.

內存單元的分配.所有的內存分配均由 C 編譯器完成,分配的內存單元通過變量供 內嵌匯編器使用.內嵌匯編器不支持內嵌匯編程序中用於內存分配的偽指令.

SWI和 BL 指令.在內嵌的 SWI 和 BL 指令中,除了正常的操作數域外,還必須增加以 下 3 個可選的寄存器列表:

* 第 1 個寄存器列表中的寄存器用於輸入的參數.

* 第 2 個寄存器列表中的寄存器用於存儲返回的結果

* 第 3 個寄存器列表中的寄存器的內容可能被被調用的子程序破壞,即這些寄存 器是供被調用的子程序作為工作寄存器

內嵌匯編器與 armasm 匯編器的差異

內嵌匯編器不支持通過“.”指示符或 PC 獲取當前指令地址;不支持 LDR Rn,=expr 偽指令,而使用 MOV Rn,expr 指令向寄存器賦值;不支持標號表達式;不支持 ADR 和 ADRL 偽指令;不支持 BX 指令;不能向 PC 賦值.

使用 0x 前綴代替”&”,表示十六進制數.使用 8 位移位常數導致 CPSR 的標志更新 時,N、Z、C 和 V 標志中的 C 不具有真實意義.

內嵌匯編注意事項

< 必須小心使用物理寄存器,如 R0~R3,IP,LR 和 CPSR 中的 N,Z,C,V 標志位.因 為計算匯編代碼中的 C 表達式時,可能會使用這些物理寄存器,並會修改 N,Z,C,V 標志位.如:

asm

{ MOV R0,x

ADD y,R0,x/y //計算 x/y 時 R0 會被修改

}

在計算 x/y 時 R0 會被修改,從而影響 R0+x/y 的結果.用一個 C 程序的變量代替 R0

就可以解決這個問題:

asm

{

MOV var,x

ADD y,var,x/y

}

內嵌匯編器探測到隱含的寄存器沖突就會報錯.

< 不要使用寄存器代替變量.盡管有時寄存器明顯對應某個變量,但也不能直 接使用寄存器代替變量.

int bad_f(int x) //x 存放在 R0 中

{

asm

{

}

ADD R0,R0,#1 //發生寄存器沖突,實際上 x 的值沒有變化

return(x);

}

盡管根據編譯器的編譯規則似乎可以確定 R0 對應 x,但這樣的代碼會使內嵌匯編器

認為發生了寄存器沖突.用其他寄存器代替 R0 存放參數 x,使得該函數將 x 原封不動地返回.

這段代碼的正確寫法如下:

int bad_f(intx)

{ asm

{

ADD x,x,#1

}

return(x)

}

< 使用內嵌式匯編無需保存和恢復寄存器.事實上,除了 CPSR 和 SPSR 寄存器,

對物理寄存器先讀后寫都會引起匯編器報錯.例如.:

int f(int x)

{ asm

{

STMFD SP!{R0} //保存 R0.先讀后寫,匯編出錯 ADD R0,x,1

EOR x,R0,x

LDMFD SP!,{R0}

}

returnt(x):

}

LDM 和 STM 指令的寄存器列表中只允許使用物理寄存器.內嵌匯編可以修改處理器 模式,協處理器模式和FP,SL,SB等APCS寄存器.但是編譯器在編譯時並不了解這些變化, 所以必須保證在執行 C 代碼前恢復相應被修改的處理器模式.

< 匯編語言中的”.”號作為操作數分隔符號.如果有C表達式作為操作數,若 表達式包含有“.”必須使用“(”號和“)”號將其歸納為一個匯編操作數。例如:

_asm

{

ADD x,y,(f(),z) //“f(),z”為一個帶有“.”的 C 表達式

}

訪問全局變量

使用 IMPORT 偽指令引入全局變量,並利用 LDR 和 STR 指令根據全局變量的地址訪問 它們,對於不同類型的變量,需要采用不同選項的 LDR 和 STR 指令:

unsigned char LDRB/STRB

unsigned short LDRH/STRH

unsingned

int

LDR/STR

char

LDRSB/STRSB

short

LDRSH/STRSH

對於結構,如果知道各個數據項的偏移量,可以通過存儲/加載指令訪問.如果結構 所占空間小於 8 個字,可以使用 LDM 和 STM 一次性讀寫.

下面例子是一個匯編代碼的函數,它讀取全局變量 globval,將其加 1 后寫回. 訪問 C 程序的全局變量:

AREA globats,CODE,READONLY] EXPORT asmsubroutime

IMPORt glovbvar ;聲明外部變量 glovbvar

asmsubroutime

LDR R1,=glovbvar ;裝載變量地址 LDR R0,[R1] ;讀出數據

ADD R0,R0,#1 ;加1 操作 STR R0,[R1] ;保存變量值 MOV PC LR

END

C 與匯編相互調用

在 C 程序和 ARM 匯編程序之間相互調用必須遵守 ATPCS.使用 ADS 的 C 語言編譯器編譯的C語言子程序滿足用戶指定的ATPCS類型.而對於匯編語言來說,完全要依賴用戶 來保證各個子程序滿足選定的 ATPCS 類型.具體來說,匯編語言子程序必須滿足下面 3 個條件:

< 在子程序編寫時必須遵守相應的 ATPCS 規則

< 堆棧的使用要遵守相應的 ATPCS 規則.

< 在匯編編譯器中使用-apcs 選項

基本 ATPCS 規定了在子程序調用時的一些基本規則,包括:各寄存器的使用規則及 其相應的名稱,堆棧的使用規則,參數傳送的規則.

寄存器的使用規則

< 子程序間通過寄存器 R0~R3 來傳遞參數.這時,寄存器 R0~R3 可記作 A0~A3. 被調用的子程序在返回前無須恢復寄存器 R0~R3 的內容.

< 在子程序中,使用寄存器 R4~R11 來保存局部變量.這時,寄存器 R4~R11 可以記作 V1~V8.如果在子程序中使用了寄存器 V1~V8 中的某些寄存器,子程序進入時必須保存這些寄存器的值,在返回前必須恢復這些寄存器的值.在 Thumb 程序中,通常 只能使用寄存器 R4~R7 來保存局部變量.

< 寄存器 R12 用作過程調用中間臨時寄存器,記作 IP.在子程序間的連接代碼 段中常有這種使用規則.

< 寄存器 R13 用作堆棧指針,記作 SP.在子程序中寄存器 R13 不能作其他用途. 寄存器 SP 在進入子程序時的值和退出子程序時的值必須相等.

< 寄存器 R14 稱為連接寄存器,記作 LR.它用於保存子程序的返回地址.如果 在子程序中保存了返回地址,寄存器 R14 則可以用作其他用途.

< 寄存器 R15 是程序計數器,記作 PC.它不能用作其它用途.

堆棧使用規則

ATPCS 規定堆棧為 FD 類型,即滿遞減堆棧,並且對堆棧的操作是 8 字節對齊. 使用ADS中的編譯器產生的目標代碼中包含了DRAFT2格式的數據幀.在調試過程中,

調試器可以使用這些數據幀來查看堆棧中的相關信息.對於匯編語言來說,用戶必須使 用 FRAME 偽指令來描述堆棧的數據幀.ARM 匯編器根據這些偽指令在目標文件中產生相 應的 DRAFT2 格式的數據幀.(堆棧中的數據幀---在堆棧中,為子程序分配的用來保存寄 存器和局部變量的區域).對於匯編程序來說,如果目標文件中包含了外部調用,則必須 滿足下列條件:

< 外部接口的堆棧必須是 8 字節對齊的.

< 在匯編程序中使用 PRESERVE8 偽指令告訴連接器,本匯編程序數據是 8 字節 對齊的.

參數傳遞規則

根據參數個數是否固定可以將子程序分為參數個數固定的子程序和參數個數可變 化的子程序.這兩種子的參數傳遞規則是不一樣的.

< 參數個數可變的子程序參數傳遞規則 對於參數個數可變的子程序,當參數不超過4個時,可以使用寄存器R0~R3來傳遞參

數;當參數超過 4 個時,還可以使用堆棧來傳遞參數. 在參數傳遞時,將所有參數看作是存放在連續的內存字單元的字數據.然后,依次將

各字數據傳送到寄存器R0,R1,R2,R3中,如果參數多於4個,將剩余的字數據傳送堆棧中, 入棧的順序與參數順序相反,即最后一個字數據先入棧.

按照上面的規則,一個浮點數參數可以通過寄存器傳遞,也可以通過堆棧傳遞,也可 能一半通過寄存器傳遞,另一半通過堆棧傳遞.

< 參數個數固定的子程序參數傳遞規則

對於參數個數固定的子程序,參數傳遞與參數個數可變的子程序參數傳遞規則不

同.

如果系統包含浮點運算的硬件部件,浮點參數將按下面的規則傳遞; 各個浮點參數按順序處理;

為每個浮點參數分配 FP 寄存器; 分配的方法是,滿足該浮點參數需要的且編號最小的一組連續的 FP 寄存器 第一個整數參數,通過寄存器 R0~R3 來傳遞.其他參數通過堆棧傳遞.

< 子程序結果返回規則 子程序中結果返回的規則如下;

結果為一個 32 位的整數時,可以通過寄存器 R0 返回; 結果為一個 64 位的整數時,可以通過寄存器 R0 和 R1 返回; 結果為一個浮點數時,可以通過浮點運算部件的寄存器 f0,d0 或 s0 來返回; 結果為復合型的浮點(如復數)時,可以通過寄存器 f0~fnA 或 d0~dn 來返回; 對於位數更多的結果,需要通過內存來傳遞.

C 程序調用匯編程序

匯編程序的設置要遵循 ATPCS 規則,保證程序調用時參數的正確傳遞.

< 在匯編程序中使用 EXPORT 偽指令聲明本子程序,使其它程序可以調用此子 程序.

< 在 C 語言程序中使用 extern 關鍵字聲明外部函數(聲明要調用的匯編子程序),即可調用此匯編子程序.

如以下程序所示,匯編子程序 strcopy 使用兩個參數,一個表示目標字符串地址,一 個表示源字符串的地址,參數分別存放 R0,R1 寄存器中.

調用匯編的 C 函數:

#include <stdio.h>

extern void strcopy(char*d,const char*s) //聲明外部函數,即要調用的匯編子程序

int mian(void)

{

const char *srcstr=“First string-source”; //定義字符串常量

char dstsrt[] =“Second string-destination”;//定義字符串變量

printf(“Before copying:\n”);

printf(“’%s’\n ‘%s\n,”srcstr,dststr); //顯示源字符串和目標字符串的內容 strcopy(dststr,srcstr); //調用匯編子程序,R0=dststr,R1=srcstr printf(“After copying:\n”)

printf(“’%s’\n ‘%s\n,”srcstr,dststr); //顯示 strcopy 復制字符串結果

return(0);

}

被調用匯編子程序:

AREA SCopy,CODE,READONLY

EXPORT strcopy ;聲明 strcopy,以便外部程序引用

strcopy

;R0 為目標字符串的地址

;R1 為源字符串的地址 ;

LDRB

R2,[R1],#1

;讀取字節數據,源地址加 1

STRB

R2,[R0],#1

;保存讀取的 1 字節數據,目標地址加 1

CMP

r2,#0

;判斷字符串是否復制完畢

BNE

strcopy

;沒有復制完畢,繼續循環

MOV

pc,lr

;返回

END

匯編程序調用 C 程序

匯編程序的設置要遵循 ATPCS 規則,保證程序調用時參數的正確傳遞. 在匯編程序中使用 IMPORT 偽指令聲明將要調用的 C 程序函數.

在調用 C 程序時,要正確設置入口參數,然后使用 BL 調用. 以下程序清單所示,程序使用了 5 個參數,分別使用寄存器 R0 存儲第 1 個參數,R1

存儲第 2 個數,R2 存儲第 3 個參數,R3 存儲第 4 個參數,第 5 個參數利用堆棧傳送.由於 利用了堆棧傳遞參數,在程序調用用結果后要調整堆棧指針

匯編調用 C 程序的 C 函數:

/*函數 sum5()返回 5 個整數的和*/

int sum5(int a,lit b, int c,int d,int e)

{

return(a+b+c+d+e); //返回 5 個變量的和

}

匯編調用 C 程序的匯編程序:

EXPORT CALLSUM5

AREA Example, CODE,READONLY

IMPORT sum5 ;聲明外部標號 sum5,即 C 函數 sum5() CALLSUMS

STMFD

SP!{LR}

;LR 寄存器放棧

ADD

R1,R0,R0

;設置 sum5 函數入口參數,R0 為參數 a

ADD

R2,R1,R0

;R1 為參數 b,R2 為參數 c

ADD

R3,R1,R2,

STR

R3,[SP,#-4]!

;參數 e 要通過堆棧傳遞

ADD

R3,R1,R1

;R3 為參數 d

BL

sum5

;調用 sum5(),結果保存在 R0

ADD

SP,SP#4

;修正 SP 指針

LDMFD

SP,{PC

;子程序返回

END

ARM 指令集列表

ARM 存儲器訪問指令表列表

助記符

說明

操作

條件碼位置

LDR Rd,addressing

加載字數據

Rd←[addressing],addressing 索引

LDR{cond}

LDRB Rd,addressing

加載無符字節數據

Rd←[addressing],addressing 索引

LDR{cond}B

LDRT Rd,addressing

以用戶模式加載字數據

Rd←[addressing],addressing 索引

LDR{cond}T

LDRBT Rd,addressing

以用戶模式加載無符號字數據

Rd←[addressing],addressing 索引

LDR{cond}BT

LDRH Rd,addressing

加載無符半字數據

Rd←[addressing],addressing 索引

LDR{cond}H

LDRSB Rd,addressing

加載有符字節數據

Rd←[addressing],addressing 索引

LDR{cond}SB

LDRSH Rd,addressing

加載有符半字數據

Rd←[addressing],addressing 索引

LDR{cond}SH

STR Rd,addressing

存儲字數據

[addressing]←Rd,addressing 索引

STR{cond}

STRB Rd,addressing

存儲字節數據

[addressing]←Rd,addressing 索引

STR{cond}B

STRT Rd,addressing

以用戶模式存儲字數據

[addressing]←Rd,addressing 索引

STR{cond}T

STRBT Rd,addressing

以用戶模式存儲字節數據

[addressing]←Rd,addressing 索引

STR{cond}BT

STRH Rd,addressing

存儲半字數據

[addressing]←Rd,addressing 索引

STR{cond}H

LDM{mode} Rn{!},reglist

批量(寄存器)加載

reglist←[Rn…],Rn 回存等

LDM{cond}{more}

STM{mode} Rn{!},rtglist

批量(寄存器)存儲

[Rn…]← reglist,Rn 回存等

STM{cond}{more}

SWP Rd,Rm,Rn

寄存器和存儲器字數據交換

Rd←[Rd],[Rn]←[Rm](Rn≠Rd 或 Rm)

SWP{cond}

SWPB Rd,Rm,Rn

寄存器和存儲器字節數據交換

Rd←[Rd],[Rn]←[Rm](Rn≠Rd 或 Rm)

SWP{cond}B

ARM 數據處理指令列表

助記符號

說明

操作

條件碼位置

MOV Rd ,operand2

數據轉送

Rd←operand2

MOV {cond}{S}

MVN Rd ,operand2

數據非轉送

Rd←(operand2)

MVN {cond}{S}

ADD Rd,Rn operand2

加法運算指令

Rd←Rn+operand2

ADD {cond}{S}

SUB Rd,Rn operand2

減法運算指令

Rd←Rn-operand2

SUB {cond}{S}

RSB Rd,Rn operand2

逆向減法指令

Rd←operand2-Rn

RSB {cond}{S}

ADC Rd,Rn operand2

帶進位加法

Rd←Rn+operand2+carry

ADC {cond}{S}

SBC Rd,Rn operand2

帶進位減法指令

Rd←Rn-operand2-(NOT)Carry

SBC {cond}{S}

RSC Rd,Rn operand2

帶進位逆向減法指令

Rd←operand2-Rn-(NOT)Carry

RSC {cond}{S}

AND Rd,Rn operand2

邏輯與操作指令

Rd←Rn&operand2

AND {cond}{S}

ORR Rd,Rn operand2

邏輯或操作指令

Rd←Rn|operand2

ORR {cond}{S}

EOR Rd,Rn operand2

邏輯異或操作指令

Rd←Rn^operand2

EOR {cond}{S}

BIC Rd,Rn operand2

位清除指令

Rd←Rn&(~operand2)

BIC {cond}{S}

CMP Rn,operand2

比較指令

標志 N、Z、C、V←Rn-operand2

CMP {cond}

CMN Rn,operand2

負數比較指令

標志 N、Z、C、V←Rn+operand2

CMN {cond}

TST Rn,operand2

位測試指令

標志 N、Z、C、V←Rn&operand2

TST {cond}

TEQ Rn,operand2

相等測試指令

標志 N、Z、C、V←Rn^operand2

TEQ {cond}

ARM 乘法指令列表

助記符

說明

操作

條件碼位置

MUL Rd,Rm,Rs

32 位乘法指令

Rd←Rm*Rs (Rd≠Rm)

MUL{cond}{S}

MLA Rd,Rm,Rs,Rn

32 位乘加指令

Rd←Rm*Rs+Rn (Rd≠Rm)

MLA{cond}{S}

UMULL RdLo,RdHi,Rm,Rs

64 位無符號乘法指令

(RdLo,RdHi)←Rm*Rs

UMULL{cond}{S}

UMLAL RdLo,RdHi,Rm,Rs

64 位無符號乘加指令

(RdLo,RdHi)←Rm*Rs+(RdLo,RdHi)

UMLAL{cond}{S}

SMULL RdLo,RdHi,Rm,Rs

64 位有符號乘法指令

(RdLo,RdHi)←Rm*Rs

SMULL{cond}{S}

SMLAL RdLo,RdHi,Rm,Rs

64 位有符號乘加指令

(RdLo,RdHi)←Rm*Rs+(RdLo,RdHi)

SMLAL{cond}{S}

ARM 跳轉指令列表

助記符

說明

操作

條件碼位置

B label

跳轉指令

Pc←label

B{cond}

BL label

帶鏈接的跳轉指令

LR←PC-4, PC←label

BL{cond}

BX Rm

帶狀態切換的跳轉指令

PC←label,切換處理狀態

BX{cond}

clip_image020ARM 協處理器指令列表

助記符

說明

操作

條件碼位置

CDP

coproc,opcodel,CRd,CRn,CRm{,opcode2}

協處理器數據操作指令

取決於協處理器

CDP{cond}

LDC{L} coproc,CRd〈地址〉

協處理器數據讀取指令

取決於協處理器

LDC{cond}{L}

STC{L} coproc,CRd,〈地址〉

協處理器數據寫入指令

取決於協處理器

STC{cond}{L}

MCR coproc, opcodel,Rd,CRn,{,opcode2}

ARM 寄存器到協處理器寄存

器的數據傳送指令

取決於協處理器

MCR{cond}

MRC coproc, opcodel,Rd,CRn,{,opcode2}

協處理器寄存器到 ARM 寄存

器到數據傳送指令

取決於協處理器

MCR{cond}

ARM 雜項指令列表

助記符

說明

操作

條件碼位置

SWI immed_24

軟中斷指令

產生軟中斷,處理器進入管理模式

SWI{cond}

MRS Rd,psr

讀狀態寄存器指令

Rd←psr,psr 為 CPSR 或 SPSR

MRS{cond}

MSR psr_fields,Rd/#immed_8r

寫狀態寄存器指令

psr_fields←Rd/#immed_8r,psr 為

CPSR 或 SPSR

MSR{cond}

ARM 偽指令列表

偽指令助記符

說明

操作

條件碼位置

ADR register,expr

小范圍的地址讀取偽指令

register<-expr 指向的地址

ADR{cond}

ADRL register,expr

中等范圍的地址讀取偽指令

register<-expr 指向的地址

ADR{cond}

LDR

register,=expr/label-expr

大范圍的地址讀取偽指令

register<-expr/label-expr 指定

的數據/地址

LDR{cond}

NOP

空操作偽指令

Thumb 指令集列表

Thumb 存儲器訪問指令列表

助記符

說明

操作

影響標志

LDR Rd,[Rn,#immed_5×4]

加載字數據

Rd←[Rm,#immed_5×4],Rd,Rn 為 R0~R7

LDRH Rd,[Rn,#immed_5×2]

加載無符半字數據

Rd←[Rm,#immed_5×2],Rd,Rn 為 R0~R7

LDRB Rd,[Rn,#immed_5×1]

加載無符字節數據

Rd←[Rm,#immed_5×1],Rd,Rn 為 R0~R7

STR Rd,[Rn,#immed_5×4]

存儲字數據

Rn,#immed_5×4Rd←Rd,Rn 為 R0~R7

STRH Rd,[Rn,#immed_5×2]

存儲無符半遼數據

Rn,#immed_5×2]Rd←Rd,Rn 為 R0~R7

STRB Rd,[Rn#immed_5×1]

存儲無符字節數據

Rn,#immed_5×1]Rd←Rd,Rn 為 R0~R7

LDR Rd,[Rn,Rm]

加載字數據

Rd←[Rn,Rm],Rd,Rn,Rm 為 R0~R7

LDRH Rd,[Rn,Rm]

加載無符半字數據

Rd←[Rn,Rm],Rd,Rn,Rm 為 R0~R7

LDRB Rd,[Rn,Rm]

加載無符字節數據

Rd←[Rn,Rm],Rd,Rn,Rm 為 R0~R7

LDRSH Rd[Rn,Rm]

加載有符半字數據

Rd←[Rn,Rm],Rd,Rn,Rm 為 R0~R7

LDRSB Rd[Rn,Rm]

加載有符字節數據

Rd←[Rn,Rm],Rd,Rn,Rm 為 R0~R7

STR Rd,[Rn,Rm]

存儲字數據

[Rn,Rm]←Rd,Rd,Rn,Rm 為 R0~R7

STRH Rd,[Rn,Rm]

存儲無符半字數據

[Rn,Rm]←Rd,Rd,Rn,Rm 為 R0~R7

STRB Rd,[Rn,Rm]

存儲無符字節數據

[Rn,Rm]←Rd,Rd,Rn,Rm 為 R0~R7

LDR Rd,[PC,#immed_8×4]

基於 PC 加載字數據

Rd←{PC,#immed_8×4]Rd 為 R0~R7

LDR Rd,label

基於 PC 加載字數據

Rd←[label],Rd 為 R0~R7

LDR Rd,[SP,#immed_8×4]

基於 SP 加載字數據

Rd←{SP,#immed_8×4]Rd 為 R0~R7

STR Rd,[SP,#immed_8×4]

基於 SP 存儲字數據

{SP,#immed_8×4]←Rd,Rd 為 R0~R7

LDMIA Rn{!}reglist

批量(寄存器)加載

regist←[Rn…],Rn 回存等(R0~R7)

STMIA Rn{!}reglist

批量(寄存器)加載

[Rn…]←reglist,Rn 回存等(R0~R7)

PUSH {reglist[,LR]}

寄存器入棧指令

[SP…]←reglist[,LR],SP 回存等(R0~R7,LR)

POP {reglist[,PC]}

寄存器入棧指令

reglist[,PC]←[SP…],SP 回存等(R0~R7,PC)

Thumb 數據處理指令列表

助記符

說明

操作

影響標志

MOV Rd,#expr

數據轉送

Rd←expr,Rd 為 R0~R7

影響 N,Z

MOV Rd,Rm

數據轉送

Rd←Rm,Rd、Rm 均可為 R0~R15

RdT 和 Rm 均為 R0~R7

時,影響 N,Z,清零 C,V

MVN Rd,Rm

數據非傳送指令

Rd←(~Rm),Rd,Rm 均為 R0~R7

影響 N,Z

NEG Rd,Rm

數據取負指令

Rd←(-Rm),Rd,Rm 均為 R0~R7

影響 N,Z,C,V

ADD Rd.Rn,Rm

加法運算指令

Rd←Rn+Rm,Rd,Rn,Rm 均為 R0~R7

影響 N,Z,C,V

ADD Rd.Rn,#expr3

加法運算指令

Rd←Rn+expr#,Rd,Rn 均為 R0~R7

影響 N,Z,C,V

ADD Rd,#expr8

加法運算指令

Rd←Rd+expr8,Rd 為 R0~R7

影響 N,Z,C,V

ADD Rd,Rm

加法運算指令

Rd←Rd+Rm,Rd,Rm 均可為 R0~R15

Rd 和 Rm 均為 R0~R7

時,影響 N,Z,C,V

ADD Rd,Rp#expr

SP/PC 加法運算指令

Rd←SP+expr 或 PC+expr,Rd 為 R0~R7

ADD SP,#expr

SP 加法運算指令

SP←SP+expr

SUB Rd,Rn,Rm

減法運算指令

Rd←Rn-Rm,Rd、Rn、Rm 均為 R0~R7

影響 N,Z,C,V

SUB Rd,Rn,#expr3

減法運算指令

Rd←Rn-expr3,RdRn 均為 R0~R7

影響 N,Z,C,V

SUB Rd,#expr8

減法運算指令

RD←Rd-expr8,Rd 為 R0~R7

影響 N,Z,C,V

SUB SP,#expr

SP 減法運算指令

SP←SP-expr

ADC Rd,Rm

帶進位加法指令

Rd←Rd+Rm+Carry,Rd、Rm 為 R0~R7

影響 N,Z,C,V

SBC Rd,Rm

帶位減法指令

Rd←Rd-Rm-(NOT)Carry,Rd、Rm 為 R0~R7

影響 N,Z,C,V

MUL Rd,Rm

乘法運算指令

Rd←Rd*Rm,Rd、Rm 為 R0~R7

影響 N,Z,

AND Rd,Rm

邏輯與操作指令

Rd←Rd&Rm,Rd、Rm 為 R0~R7

影響 N,Z,

ORR Rd,Rm

邏輯或操作指令

Rd←Rd|Rm,Rd、Rm 為 R0~R7

影響 N,Z,

EOR Rd,Rm

邏輯異或操作指令

Rd←Rd^Rm,Rd、Rm 為 R0~R7

影響 N,Z,

BIC Rd,Rm

位清除指令

Rd←Rd&(~Rm),Rd、Rm 為 R0~R7

影響 N,Z,

ASR Rd,Rs

算術右移指令

Rd←Rd 算術右移 Rs 位,Rd,Rs 為 R0~R7

影響 N,Z,C,

ASR Rd,Rm,#expr

算術右移指令

Rd←Rm 算術右移 expr 位,Rd、Rm 為 R0~R7

影響 N,Z,C,

LSL Rd,Rs

邏輯左移指令

Rd←Rd<<Rs,Rd、Rs 為 R0~R7

影響 N,Z,C,

LSL Rd,Rm,#expr

邏輯左移指令

Rd←Rm<<expr,Rd、Rm 為 R0~R7

影響 N,Z,C,

LSR Rd,Rs

邏輯右移指令

Rd←Rd>>Rs,Rd、Rs 為 R0~R7

影響 N,Z,C,

LSR Rd,Rm,#expr

邏輯右移指令

Rd←Rm>>mexpr,Rd、Rm 為 R0~R7

影響 N,Z,C,

ROR Rd,Rs

循環右移指令

Rd←Rm 循環右移 Rs 位,Rd、Rs 為 R0~R7

影響 N,Z,C,

CMP Rn,Rm

比較指令

狀態標←Rn-Rm,Rn、Rm 為 R0~R15

影響 N,Z,C,V

CMP Rn,#expr

比較指令

狀態標←Rn-expr,Rn 為 R0~R7

影響 N,Z,C,V

CMN Rn,Rm

負數比較指令]

狀態標←Rn+Rm,Rn、Rm 為 R0~R7

影響 N,Z,C,V

TST Rn,Rm

位測試指令

狀態標←Rn&Rm,Rn、Rm 為 R0~R7

影響 N,Z,C,V

Thumb 跳轉指令及軟中斷指令列表

助記符

說明

操作

條件碼位置

B label

跳轉指令

PC←label

B{cond}

BL label

帶鏈接的跳轉指令

LR←PC←4,PC←label

BX Rm

SWI immed_8

帶狀態切換的跳轉指令

軟中斷指令

PC←label 切換處理器狀態

產生軟中斷,處理器進入管理模式

Thumb 偽指令列表

偽指令助記符

說明

操作

條件碼位置

ADR register,expr

小范圍的地址讀取偽指令

register<-expr 指向的地址

LDR

register,=expr/label-expr

大范圍的地址讀取偽指令

register<-expr/label-expr 指

定的數據/地址

NOP

空操作偽指令

匯編預定義變量及偽指令

預定義的寄存器和協處理器名

ARM 匯編器對 ARM 的寄存器進行了預定義(包括 APCS 對 R0~R15 寄存器的定義), 所有的寄存器和協處理器名都是大小寫敏感.預定義的寄存器如下:

通用寄存器

R0~R15 和 r0~r15(16 個通用寄存器); a1~a4(參數,結果或臨時寄存器,同 R0~R3); v1~v8(變量寄存器,同 R4~R11);

SB 和 sb(靜態基址,同 R9); SL 和 sl(堆棧限制,同 R10); FP 和 fp(幀指針);

IP 和 ip(過程調用中間臨時寄存器,同 R12); SP 和 sp(堆棧指針,同 R13);

LR 和 lr(鏈接寄存器,同 R14); PC 和 pc(程序計數器,同 R15).

程序狀態寄存器

CPSR 和 cpsr; SPSR 和 spsr;

浮點數寄存器

F0~F7 和 f0~f7(FPA 寄存器);

S0~S7 和 s0~s7(VFP 單精度寄存器); D0~D7 和 d0~d7(VFP 雙精度寄存器);

協處理器及協處理器寄存器

p0~p15(協處理器 0~15);

c0~c15(協處理器寄存器 0~15);

內置變量列表

ARM 匯編器中定義了一些內置變量,如下表所示.這些內置變量不能使用偽指令 設置(如 SETA,SETL,SETS),一般用於程序的條件匯編控制等,如下;

IF {CONFIG}=16

… ELSE

… ENDIF

B ;跳轉到當前地址,即死循環 內置變量表

變量

說明

{PC}或"."

當前指令的地址

{VAR}或"@"

存儲區位置計數器的當前值

{TRUE}

邏輯真

{FALSE}

邏輯假

{OPT}

當前設置列表選項值.OPT 用來保存當前列表選項,改變選項值,或恢復原始值

{CONFIG}

如果匯編器匯編 ARM 代碼,則值為 32;若是匯編 Thumb 代碼,則值為 16

{ENDLAN}

如果匯編器在大端模式下,則值為 big;若在小端模式下,否則為 little

{CODESIZE}

如果匯編 Thumb 代碼,則值為 16,否則為 32.同{CONFIG}變量

{CPU}

選定的 CPU 名,缺省為 ARM7TDMI.如果用命令行-cpu 選項,則為 genericARM

{FPU}

設定的 FPU 名,缺省為 SoftVFP

{ARCHITECTURE}

選定的 ARM 體系結構的值,如 3,3M,4,4T,4TxM

{PCSTOREOFFSET}

STR pc,[…]或 STR Rb,{…PC}指令的地址和 PC 的存儲值之間的偏移量

{ARMASM_VERSION}或|ads$

version|

ARM ASM 的版本號,為整數

clip_image021clip_image022

偽指令列表

偽指令類型

偽指令

功能

符號定義指 示符

GBLA

聲明一個全局的算術變量,並將其初始化為 0

GBLL

聲明一個全局的邏輯變量,並將其初始化為{FALSE}

GBLS

聲明一個全局的字符串變量,並將其初始化為空字符串""

LCLA

聲明一個局部的算術變量,並將其初始化為 0

LCLL

聲明一個局部的邏輯變量,並將其初始化為{FALSE}

LCLS

聲明一個局部的字符串變量,並將其初始化為空字符串""

SETA

給一個全局/局部的算術變量賦值

SETL

給一個全局/局部的邏輯變量賦值

SETS

給一個全局/局部的字符串變量賦值

RLIST

為一個通用寄存器列表定義名稱

CN

給一個協處理器寄存器命名,協處理器寄存器編號為 0~15

CP

為一個協處理器定義名稱,協處理器編號為 0~15

DN

為一個雙精度的 VFP 寄存器定義名稱

SN

為一個單精度的 VFP 寄存器定義名稱

FN

為一個 FPA 浮點寄存器定義名稱

數據定義指 示符

LTORG

聲明一個文字池

MAP或^

定義一個機構化的內存表首地址

FIELD或#

定義機構化內存表中的一個數據域

SPACE或%

分配一塊內存空間,並用 0 初始化

DCB或=

分配一段字節的內存單元,並用指定的數據初始化

DCD或&

分配一段字的內存單元,並用指定的數據初始化

DCDU

分配一段在字的內存單元,並用指定的數據初始化(不需要字對齊)

DCDO

分配一段字的內存單元,將每個單元的內容初始化為該單元相對於靜態基地址

寄存器的偏移量

DCFD

分配一段雙字的內存單元,並用雙精度的浮點數初始化

DCFDU

分配一段雙字的內存單元,並用雙精度的浮點數據初始化(不需要字對齊)

DCFS

分配一段字的內存單元,並用單精度的浮點數據初始化

DCFSU

分配一段字的內存單元,並用單精度的浮點數據初始化(不需要字對齊)

DCI

分配一段字節的內存單元,用指定的數據初始化,指定內存單元存放的是代碼

而不是數據

DCQ

分配一段雙字的內存單元,並用 64 位的整數數據初始化

DCQU

分配一段雙字的內存單元,並用 64 位的整數數據初始化(不需要字對齊)

DCW

分配一段半字的內存單元,並用指定的數據初始化

DCWU

分配一段半字的內存單元,並用指定的數據初始化(不需要字對齊)

報告指示符

ASSERT

在匯編編譯器對匯編程序的第二遍掃描中,如果 ASSERT 條件不成立,ASSERT

偽指令將報告該錯誤信息

INFO或!

在匯編編譯器對匯編程序的第一遍或第二遍掃描時報告診斷信息

OPT

在源程序中設置列表選項

clip_image023clip_image024clip_image020[1]clip_image020[2]clip_image025clip_image026

TTL

在列表文件中的每一頁的開頭插入一個標題

SUBT

在列表文件中的每一頁的開頭插入一個子標題

匯編控制指 示符

IF或[

IF、ELSE 和 ENDIF 偽指令能夠根據條件把一段源代碼包括在匯編源程序內或將 其排除在外

ELSE或|

ENDIF或]

MACRO

MACRO 和 MEND 偽指令用於宏定義

MEND

MEXIT

退出宏定義

WHILE

WHILE 和 WEND 偽指令用於根據條件重復匯編相同的或幾乎相同的一段源代碼

WEND

雜項指示符

ALIGN

通過添加補丁字節使當前位置滿足一定的對齊方式

AREA

定義一個代碼段或數據段

CODE16

指示匯編編譯器后面的指令為 16 位的 Thumb 指令

CODE32

指示匯編編譯器后面的指令為 32 位的 ARM 指令

END

指示匯編編譯器源文件已結束

ENTRY

指定程序入口點

EQU或*

為數字常量、基於寄存器的值和程序中的標號定義一個名稱

EXPORT或

GLOBAL

聲明一個符號可以被其它文件引用。相當於生命了一個全局變量

IMPORT或

EXTERN

指示編譯器當前的符號不是在本源文件中定義的,而是在其它源文件中定義

的,在本源文件中可能引用該符號

GET或

INCLUDE

將一個源文件包含到當前源文件中,並將被包含的文件在其當前位置進行匯編

處理

INCBIN

將一個文件包含到當前源文件中,而被包含的文件不進行和匯編處理

KEEP

指示編譯器保留符號表中的局部符號

NOFP

禁止源程序中包含浮點運算指令

REQUIRE

指定段之間的依賴關系

REQUIRE8

指示當前文件請求堆棧為 8 字節對齊

PRESERVE8

指示當前文件保持堆棧為 8 字節對齊

RN

給一個特殊的寄存器命名

ROUT

定義局部標號的有效范圍

ARM 偽指令

ADR

小范圍的地址讀取偽指令

ADRL

中等范圍的地址讀取偽指令

LDR

大范圍的地址讀取偽指令

NOP

空操作偽指令

Thumb 偽指令

ADR

中等范圍的地址讀取偽指令

LDR

大范圍的地址讀取偽指令

NOP

空操作偽指令

指令條件碼列表

條件碼助記符

標志

含義

EQ

Z=1

相等

NE

Z=0

不相等

CS/HS

C=1

無符號數大於或等於

CC/LO

C=0

無符號數小於

MI

N=1

負數

PL

N=0

正數或零

VS

V=1

溢出

VC

V=0

沒有溢出

HI

C=1,Z=0

無符號數大於

LS

C=0,Z=1

無符號數小於或等於

GE

N=V

帶符號數大於或等於

LT

N!=V

帶符號數小於

GT

Z=0,N=V

帶符號數大於

LE

Z=1,N!=V

帶符號數小於或等於

AL

任何

無條件執行(指令默認條件)

clip_image027clip_image028clip_image029clip_image030clip_image031clip_image032clip_image033clip_image034常用 ARM 指令集及匯編 Ver1.0.12

CPSR 和 SPSR 分配圖

CPSR 或 SPSR 模式常量定義:

CPSR_f 或 SPSR_f

CPSR_s 或 SPSR_s

CPSR_x 或 SPSR_x

CPSR_c 或 SPSR_c

31

30

29

28

27

26

25

24

23

22

21

20

19

18

17

16

15

14

13

12

11

10

09

08

07

06

05

04

03

02

01

00

N

Z

C

V

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

I

F

T

M4

M3

M2

M1

M0

負數或小於

進位或借位或擴展

溢 出

保留位

禁止 禁止 '允許

禁止 禁止 '允許

狀態位

模式位

10000-0x0010-用戶

10001-0x0011-快速中斷

10010-0x0012-中斷

10011-0x0013 管理

10111-0x0017-未定義

11111-0x001F-系統


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM