1、ADS1.2 ---> ARM7 + ARM9 + ARM9E
2、MDK5.1 ---> ARM7 + ARM9 + ARM9E + Cortex-M0、M3、M4
3、IAR --->ARM7 + ARM9 + ARM9E + Cortex-M0、M3、M4
4、RVDS --->支持ARM7、ARM9、4、ARM10、ARM11、Cortex等全系列ARM内核
5、GNU --->arm-linux-gcc
看到这里就有有人会问,为啥不用RVDS做开发,这个原因请淘宝一下~
RISC架构:
1)每条汇编指令编译成的机器码是等长的(ARM:32bits;THUMB:16bits)--->执行的效率高,代码的密度低。
2)指令数少,绝大部分指令是重复使用
ARM汇编指令的编码格式:
条件码:
ARM汇编指令的后面都可以加条件,条件的判断依据---->CPSR(NZCV)
1、数据处理指令
完成通用寄存器(R0~R15)与立即数之间的数据运算及处理。
1)算术运算指令
ADD R1, R2, #10 //R1=R2+10
SUB R3,R2,R1 //R3=R2-R1
AND R1,R1,#0x3// R1=R1&0x3
ORR R1,R1,#3 // R1=R1 | 0x3
BIC R1,R1,#3 //R1=R1&(~3)
EOR R1,R1,#3 //立即寻址R1=R1^3
RSB R3,R2,R1 //寄存器寻址 R3=R1-R2 逆向减法
错误的写法:
ADD R2, #10, #20
SUB R1,#10,R2
2)比较指令 ---->不需要加”S”,会自动影响条件码标志位
CMP R1, #10 //类似于 SUBS R2, R1, #10
TEQ R1, #10
TST R1, #8
3)传输指令
MOV R1, #10
MVN R1, #10
注意:
在数据处理指令中,立即数有要求的,并不是所有的立即数都是合法的。例如,以下ARM汇编指令是非法,原因是立即数不合法。
ADD R5,R5,#0x123
MOV R5, #0x345
CMP R6, #0x678
立即数合法的条件:
1)如果立即数是小于256(0x100)的,即该立即数可以用8bits的二进制数描述。
2)如果立即数大于256,但是该立即数经过循环左移偶数位,可以得到一个小于256的数,则该立即数合法。
例:BIC R1, R1, #0xffff //不合法
解决方法1:
BIC R1, R1, #0xff
BIC R1, R1, #0xff00
解决方法2:
LDR R0, =0xffff //mov r0, #0xffff不合法
BIC R1,R1,R0
2、数据加载和数据存储指令
完成通用寄存器和存储器之间的数据传递。通过一个地址来访问该地址下的数据,相当于C语言的指针。
LDR ---->loader 将一个地址下的数据加载到通用寄存器,采用的寻址方式是间接寻址。相应于C语言的指针。
STR ----->store,loader的反方向。
例:
LDR R0, =0xe0200280 //LDR是ARM汇编伪指令,实现了将0xe0200280传到R0
LDR R1, [R0] //LDR是ARM汇编指令,将0xe0200280地址下的数据加载给R1。
LDR R2, [R0, #4] //将0xe0200280+4地址下的数据加载给R2。基址変址寻址
LDR R1,[0xe0200280] //错误
STR R2, [R0] //将R2的内容存储到R0的地址下。
注意:
LDR和STR是字类型的数据的加载和存储。
LDRB和STRB是字节类型数据的加载和存储
LDRH和STRH是半字节类型数据的加载和存储
----------------------------------------------------------------------
3、跳转指令--->分支指令
B ----> 直接跳转,跳转的同时不保存返回地址。
BL -----> 在跳转之前保存返回地址到LR(R14),然后在跳转
BX ---->带有工作状态切换的跳转。ARM状态<---->THUMB状态
注意:
受B跳转指令编码格式的限制,B在跳转的时候是范围限制的+-32MB
4、状态寄存器的访问指令
完成状态寄存器(CPSR和SPSR)与通用寄存器(R0~R15)之间的数据传递
MSR ----> mov Status form Register
MRS ----> mov Register form Status
例:(思考)---->关闭IRQ中断
MRS R0, CPSR
ORR R0,R0,#(1<<7)
MSR CPSR, R0
不能如下:
ORR CPSR, CPSR ,#(1<<7)
5、乘法指令和乘加指令
完成通用寄存器指令的乘法或乘加。
MUL R1,R2,R3 //R1=R2*R3
MUL R1,R2,#4 //错误
MLA R1,R2,R3,R4 //R1=R2*R3+R4
6、批量的数据处理指令 --->栈的寻址
LDM --->多个LDR
STM --->多个STR
一般使用这些指令来操作stack
提出问题:stack的类型
8.数据交换指令
SWP R0,R1,[R2] //Load R0 with the word addressed by R2, and store R1 at R2.
相当于:
LDR R0,[R2]
STR R1, [R2]
SWP ---- 字类型数据的交换
SWPB ---- 字节类型数据的交换
=========================================================
ARM汇编伪指令相当于ARM汇编指令的集合。一个ARM汇编指令可能相当于几条ARM汇编指令及数据组成的一个序列。
ARM汇编伪指令经过编译器编译后,后生成ARM汇编指令及数据。
1、NOP
MOV R0,R0 替代
2、LDR
1)LDR R0, =0xe0200280
首先将数据0xe0200280放到一个地址下,然后再通过数据加载指令(LDR)根据地址加载地址下的数据。由8个字节组成 4-->加载数据的汇编指令
4-->存放数据 --->文字池(literal pool)
2)LDR PC,=test
读取test符号的地址,送给PC,实现程序的跳转,用来替代B。
=========================================================
三、ARM汇编伪操作
特别注意:ARM汇编伪操作是和开发环境有关系的。不同的开发环境,伪操作是有不同的。
.global ---->声明一个符号是全局的。
.text --->说明代码段
=========================================================
四、ARM汇编和C混合编程
1、汇编调用C
1)汇编源文件:
.text
.global _start //声明_start是全局的。这样编译器可以得到_start
_start:
//1.GPJ2_2 --->output ,GPJ2CON[11:8]=0001
LDR R0, =0xe0200280 //R0=0xe0200280
LDR R1, [R0] //将0xe0200280地址下的内容,加载给R1
BIC R1, R1,#(0xf<<8) //bit clear. R1 = R1 & (~0xf00) --->GPJ2CON[11:8]=0000
ORR R1,R1,#(1<<8) //按位或。R1=R1|0x100
STR R1,[R0] //将改写后的R1,写到0xe0200280地址下。str---store
main_loop:
//2.GPJ2_2 ouput 翻转
LDR R0, =0xe0200280
ldr R3,[R0,#4] //0xe0200280 +4
eor R3,R3,#(1<<2) //R3=R3^0x4
str R3,[R0,#4]
MOV R0, #0x200000 // r0 -----> val
bl delay //调用C的一个void delay(int val)
B main_loop
2)C源程序
void delay(int val)
{
int i;
for(i=val;i>0;i--);
}
2、C调用汇编
1)C的源程序
#define GPJ2CON (*(volatile unsigned int *)0xe0200280)
#define GPJ2DAT (*(volatile unsigned int *)0xe0200284)
extern void delay(int val);
void _start(void)
{
//GPJ2_2 --->output ,GPJ2CON[11:8]=0001
GPJ2CON &= ~(0xf<<8);
GPJ2CON |= (0x1<<8);
while(1)
{
//GPJ2_2 ouput 翻转
GPJ2DAT ^= (1<<2);
delay(0x3000000);
}
}
2)汇编源程序
.global delay
delay:
SUBS R0,R0,#1
BNE delay
mov pc,lr