1、ARM指令(注意!并不包含Thumb指令)
指令分类: 分支指令、数据处理指令、程序状态寄存器(CPSR)处理指令、加载/存储指令、协处理器指令、异常产生指令六大类。
下表为基本ARM指令,不包括派生的ARM指令:
2、ARM指令格式:
<opcode> {condition} {S} {Rd}, Operand1, Operand2
-----------------------------------------------------------------------
<opcode> //操作码。如ADD表示算术加操作指令
{condition} //条件码。决定指令执行的条件(可省略)
{S} //指令执行时是否更新CPRS寄存器的值(可省略)
必须有空格
{Rd} //目的寄存器。存储指令计算结果
Operand1 //第一个操作数。可以是一个寄存器或一个立即数
Operand2 //第二个(可变)操作数
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
条件码:
3、ARM指令中的移位操作符
对通用寄存器进行移位操作的格式如下:
Rm, <opsh>#<shift>
--------------------------------------------------
其中,Rm为要移位的通用寄存器;<opsh>为移位操作符,如下表;<shift>为移位次数,移位次数为0-31。
• 1
• 2
• 3
4、ARM指令的寻址方式
立即寻址: 操作数本身包含在指令中
MOV R0, #1314 //后面是立即数(常数)以#号作为前缀
• 1
寄存器寻址: 寄存器中的数值作为操作数
MOV R0, R1 //都为寄存器
ADD R0,R1,R2 //R0 = R1+R2
• 1
• 2
寄存器间接寻址: 寄存器中的值作为地址,再通过这个地址去取得操作数
LDR R0, [R1] //后面是地址指针,在中括号中
• 1
基址变址寻址: 将寄存器中的值与指令中给出的地址偏移量相加,从而得到一个新的地址,再通过这个地址去取得操作数
LDR R0, [R1, #-4] //后面是地址指针,中括号中为立即寻址
• 1
多寄存器寻址: 可以一次完成最多16个寄存器值的传送。
LDMIA R0, {R1,R2,R3 } //R1 <- [R0]; R2 <- [R0+4]; R3 <- [R0+8];
• 1
相对寻址: 在寄存器寻址得到操作数后再进行移位操作,得到最终的操作数
MOV R0,R2,LSL #3 //R2左移3位,结果赋给R0
• 1
堆栈寻址: 先进后出方式,使用堆栈指针指示当前操作位置,堆栈指针总是指向栈顶
四种类型的堆栈工作方式:
满递增堆栈:堆栈指针指向最后压入的数据,且由低地址向高地址生成
满递减堆栈:堆栈指针指向最后压入的数据,且由高地址向低地址生成
空递增堆栈:堆栈指针指向下一个将要放入数据的空位置,且由低地址向高地址生成
空递减堆栈:堆栈指针指向下一个将要放入数据的空位置,且由高地址向低地址生成
STMFD SP!, {R1-R7, LR} //将R1-R7,LR压入堆栈。满递减堆栈
• 1
5、ARM处理器支持的伪指令
指令 | 说明 |
---|---|
ADR | 用于相对偏移地址加载到通用寄存器中 |
LDR | 用于一个32位常数的加载或地址的加载 |
NOP | 产生空操作,用于简单延时 |
6、汇编程序设计
顺序程序设计
START LDR R0,=0x12345678 ;R0=0x12345678
LDR R1,=0x30100000 ;R1=0x30100000
LDR R2,=0x87654321 ;R2=0x87654321
STR R2,[R1] ;把R2中的数据写入R1指示的内存单元0x30100000中
LDR R3,[R1] ;取R1指示区域的数据到R3,即数据0x87654321
AND R3,R3,#0x000000FF ;R3的值与0x87654321与0x000000FF相与后得到R3=0x00000021
ADD R0,R0,R3,LSL #2 ;将R3左移2位后得到0x00000084,与R0相加结果返回R0,因此R0=0x123456FC
STR R0,[R1] ;R0中的值存入0x00100000开始的区域
END
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
分支程序设计
CMPA LDR R0,=0X30007000 ;指向首地址
LDR R1,[R0] ;取第一个数a
LDR R2,[R0+4] ;取第二个数b
CMP R1,R2 ;第一个数与第二个数比较
BHI NEXT1 ;a大于等于b,则跳转
STR R2,[R0] ;a,b交换
STR R1,[R0+4] ;a,b交换
NEXT1 LDR R1,[R0+4] ;取中间的数
LDR R2,[R0+8] ;取第三个数
CMP R1,R2 ;b大于等于c
BHI NEXT2
STR R2,[R0+4] ;b,c交换
STR R1,[R0+8] ;b,c交换
NEXT2 ……
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
循环程序设计
计算1-200的整数累加之和,并将结果存入字变量SUM中
SUM DCD 0 ;定义32位字变量SUM并赋值为0
ENTRY
CODE32 ;32位ARM模式代码
LOOPS LDR R0,=200 ;循环次数
MOV R1,#0 ;累加和清楚
LOPPA ADD R1,R1,R0 ;累加操作和在R1中
SUBS R0,R0,#1 ;计数减1,产生标志进CPSR
BCC LOPPA ;不满200继续循环
LDR R0,=SUM ;变量指针指向R0
STR R1,[R0] ;结果存入SUM中
END
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
7、嵌入式C语言与汇编语言混编
实际应用中,关键底层的初始化部分和驱动使用汇编语言,主要的编程任务一般使用C语言完成。
在C语言中嵌入汇编语言的语法格式:
__ASM //注意,是双下划线
{
汇编指令序列;
}
• 1
• 2
• 3
• 4
代码实例:
void Enable_disable_IRQ(int Selector)
{
int tmp;
if (Selector == 0)
{
/*嵌入关中断汇编程序*/
__asm //双下划线
{
MRS tmp,CPSR ;读CPSR状态寄存器的值到tmp
ORR tmp,tmp,#0x80 ;置位b7(I)以关中断
MSR CPSR_C,tmp ;写入CPSR寄存器C域中,以正式关中断
}
}
else
{
/*嵌入开中断汇编程序*/
__asm //双下划线
{
MRS tmp,CPSR ;读CPSR状态寄存器的值到tmp
BIC tmp,tmp,#0x80 ;清b7(I)以开中断
MSR CPSR_C,tmp ;写入CPSR寄存器C域中,以正式开中断
}
}
}
main()
{
Enable_disable_IRQ(0) ;关中断
…… ;初始化操作
Enable_disable_IRQ(1) ;开中断
while(1)
{
…… ;循环主体
}
}
• 1
• 2
• 3
• 4
• 5
• 6
• 7
• 8
• 9
• 10
• 11
• 12
• 13
• 14
• 15
• 16
• 17
• 18
• 19
• 20
• 21
• 22
• 23
• 24
• 25
• 26
• 27
• 28
• 29
• 30
• 31
• 32
• 33
• 34