本帖最后由 himol 于 2015-10-30 14:50 编辑
首先分享下我的学习心得:本人有过51 、32、k60。但是对于ARM从来没有一个清楚地认识。通过这次的剖析,我对ARM的认识更加深刻。希望我的学习历程对大家,特别是初学者有帮助。如果让我对ARM进行一句话的总结,我可能会说:“ARM就像所有ARM内核的游戏规则一样,你要玩游戏必须遵守规则”回归正题:
一、准备工作:
(详细过程请参考:《ok210详细(烧写)裸奔过程》)
(一)开发环境
1、 学习过简单的C语言和ARM汇编语言。
2、 开发平台:windows xp +虚拟机VMware,使用arm‐linux‐gcc4.4.1编译代码。
3、 配套开发板:OK210开发板+Android(linux)系统,所有裸机程序均在 OK210开发板上正常运行。
(二)环境搭建
1、虚拟机的安装及Ubuntu的安装与设置请按照光盘资料《OK210软件手册》
说明操作。
2、OK210开发板系统烧写请按照光盘资料《OK210软件手册》说明操作。
二、ARM处理器工作模式
(一)工作状态
1.ARM状态,此时处理器执行32位的字对齐的ARM指令。
2.thumb 此时处理器执行16位的、半字对齐的thumb指令。
(二)数据存储
ARM 体系结构数据存储分为:大端格式和小端格式
大端格式:字数据的高字节储存在低地址中,而字数据的低字节则存放在高地中。
. 小端格式相反。
(三)指令长度
指令长度可以是:32位(ARM状态)、16位(thumb状态)
ARM微处理器支持字节(8位)、半字(16位)、字(32位)三种数据类型其中,
字需要4字节对齐(地址的低两位为0)、半字需要2字节对齐(地址的最低位为0)
(四)工作模式
1.用户模式(usr)
用于正常执行程序
2.快速中断模式(FIQ)
用于快速数据传输
3.外部中断模式(IFQ)
用于通常的中断处理
4.管理模式(svc)
操作系统使用的保护模式
5.数据访问终止模式(abt)
当数据或指令预取终止时进入该模式,可用于虚拟存储及存储保护
6.系统模式(sys)
运行具有特权的操作系统任务。
7.未定义指令终止模式(und)
当未定义的指令执行时进入该模式,可用于支持硬件。
ARM微处理器的运行模式可以通过软件改变也可以通过外部中断或异常处理改变。
应用程序运行在用户模式下,当处理器运行在用户模式下时,某些被保护的系统资源是不能被访问的。
除用户模式外,其他的6种模式称之为;非用户模式,或者特权模式(privileged modes );除用户模式和系统模式外其他的5种又称为异常模式(exception modes),常用于处理中断或异常,以及需要访问受保护的系统资源等情况。
三、ARM系统寄存器
寄存器(ARM 状态)
在ARM工作状态下,任一时刻可以访问16个通用寄存器和一到两个状态寄存器。特权模式下访问特定模式分组寄存器。详见下图:
Thumb状态下的寄存器集是ARM状态下寄存器的一个子集,程序可以直接访问8个通用寄存器(R7~R0)、程序计数器(PC)、堆栈指针(SP)、链接寄存器(LR)和CPSR 。
状态对应关系:
通用寄存器:R0~R15
R13_svc~R14_svc
R13_abt~R14_abt
R13_und~R14_und
R13_irq~R14_irq
R8_fiq~R14_fiq
不分组寄存器:
R0~R7在所有处理器模式下,访问的都是同一个物理寄存器。未分组寄存器没有被系统用于特别的用于,在任何可以采用通用寄存器的应用场合都可以使用未分组寄存器。
分组寄存器:R14~R8
程序计数器:R15(pc)
PC的值等于正在执行的指令的地址+8(因为在取地址和执行之间多
了一个译码的阶段)
状态寄存器:
CPSR
SPSR_svc
SPSR_abt
SPSR_und
SPSR_irq
SPSR_fiq
ARM所有工作模式下都可以访问程序的状态寄存器CPSR。CPSR包含条件码标志、中断禁止位、当前处理器模式以及其它状态和控制信息。
CPSR在每种异常模式下都有一个对应的物理寄存器——程序状态保存寄存器SPSR。当异常出现时,其用于保存CPSR的值,以便异常返回后恢复异常发生时的工作状态。
四、ARM寻址方式
所为寻址:就是根据指令查找物理地址信息的方式
(一)立即寻址
也叫立即数寻址,操作数本身就在指令中给出。
ADD R0,R0,#1
ADD R0,R0,#0X3F
(二) 寄存器寻址
利用寄存器的数值作为操作数,这种寻址方式是各类处理器经常采用的一种方式,也是一种执行效率较高的寻址方式。
ADD R0,R0,R2 ; R0 < R0+R2
(三)寄存器间接寻址
以寄存器的值作为操作数的地址,二而操作数本身放在存储器中。
ADD R0,R0,[R2] ; R0 < R0+[R2]
LDR R0,[R1] ; R0 < [R1]
(四)基址变址寻址
将寄存器(该寄存器一般用于基地址寄存器)的内容与指令给出的地址偏移量相加,从而得到一个操作数的有效地址。
LDR R0 ,[R1,#4] ; R0 < [R1+4]
LDR R0 ,[R1,#4]! ; R1 < R1+4
LDR R0 ,[R1], #4 ; R0 < [R1] , R1
LDR R0 ,[R1,R2] ; R0 < [R1+R2]
(五)多寄存器寻址方式
一条指令可以完成多个寄存器的传送。这寄存器可以用一条指令完成最多16个通用寄存器的传送。
LDMIA R0,{R1,R2,R3,R4} ;R1<[R0]
;R2<[R0+4]
;R3<[R0+4]
;R4<[R0+4]
该指令的后缀IA表示每次执行完成加载/存储操作后,R0按字长度增加,因此指令可连续存储单元的值传送到R1~R4
(六)相对寻址
与基址变址寻址方式类似,相对寻址以程序计数器PC的当前值为基地址,指令中的地址符号作为偏移量,将两者相加之后得到操作数的有效地址。
跳转指令BL采用了相对寻址方式:
BL NEXT ;跳转到子程序的next处执行
...........
Next
.........
Move PC , LR ;从之程序返回
(七)堆栈寻址(先进后出)
使用一个称作堆栈指针的专用寄存指示当前位置,堆栈指针总是指向栈顶。
递增堆栈:向高地址方向生长
递减堆栈:(相反)
满堆栈:堆栈指针指向最后压入堆栈的有效数据项。
空堆栈:堆栈指针指向下一个要放入数据的空位置。
五、ARM汇编指令集
(一)跳转指令:
在ARM中有两种方式可以实现程序的跳转:
1.跳转指令;
2.直接向PC寄存器(R15)中写入目标地址值;通过直接向PC寄存器中写入目标地址值可以实现在4GB地址空间中任意跳转,
这种跳转指令又称为长跳转。如果在长跳转指令之前使用MOV LR,PC等指令,则可以保存将来返回的地址值,这样就
实现了在4GB地址空间中的子程序调用
ARM跳转指令可以从当前指令向前或向后的32MB地址空间跳转。这类跳转指令有以下4种。
(1)B 跳转指令 B {条件} (地址)
B指令属于ARM指令集,是最简单的分支指令。一旦遇到一个B指令,
ARM处理器将立即跳转到给定的地址,从那里继续执行。
B Lable ;程序无条件跳转到符号Label处执行
CMP R1 , #0
BEQ Label
当cpsr寄存器的z条件置位时,程序跳转到标号label处执行。
(2)BL 带返回的跳转指令 BI,〔条件) (地址)
BL指令也属于ARM指令集,是另一个分支指令。就在分支之前,在寄存器R14中装载上R15的内容,因此可以重新装载R14到R15中来
返回到这个分支之后的那个指令处执行,它是实现子例程调用的一个基本常用的手段。
(3)BLX 带返回和状态切换的跳转指令
BLX <地址>
BLX指令从ARM指令集跳转到指令中所指定的目标地址,并将处理器的工作状态有ARM状态切换到Thumb状态,该指令同时将PC的当前内容保存到寄存 器R14中。因此,当子程序使用Thumb指令集,而调用者使用ARM指令集时,可以通过BLX指令实现子程序的调用和处理器工作状态的切换。同时,子程 序的返回可以通过将寄存器R14值复制到PC中来完成。
(4)BX 带状态切换的跳转指令
BX(条件) (dest)
BX指令跳转到指令中指定的目标地址,目标地址处的指令可以是ARM指令,也可以是Thumb指令。目标地址值为指令的值和0xFl·FFFFFF做"与"操作的结果,目标地址处的指令类型由寄存器决定。
(二)数据处理
数据处理指令。数据处理指令可分为数据传送指令、算术逻辑运算指令 和比较指令等。
数据传送指令用于在寄存器和存储器之间进行数据的双向传输。
算术逻辑运算指令完成常用的算术与逻辑的运算,该类指令不但将运算结果保存在目的寄存器中,同时更新CPSR中的相应条件标志位。
比较指令不保存运算结果,只更新CPSR中相应的条件标志位。
数据处理指令共以下16条。
1、MOV指令(传送)
MOV指令的格式为:
MOV{条件}{S} 目的寄存器,源操作数
MOV指令可完成从另一个寄存器、被移位的寄存器或将一个立即数加载到目的寄存器。其中S选项决定指令的操作是否影响CPSR中条件标志位的值,当没有S 时指令不更新CPSR中条件标志位的值。
指令示例:
MOV R1,R0 ;将寄存器R0的值传送到寄存器R1
MOV PC,R14 ;将寄存器R14的值传送到 PC,常用于子程序返回
MOV R1,R0,LSL#3 ;将寄存器R0的值左移3位后传送到R1
2、MVN指令(求反)
MVN指令的格式为:
MVN{条件}{S} 目的寄存器,源操作数
MVN指令可完成从另一个寄存器、被移位的寄存器、或将一个立即数加载到目的寄存器。与MOV指令不同之处是在传送之前按位被取反了,即把一个被取反的值 传送到目的寄存器中。其中S决定指令的操作是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。
指令示例:
MVN R0,#0 ;将 立即数0取反传送到寄存器R0中,完成后R0=-1
3、CMP指令(比较)
CMP指令的格式为:
CMP{条件} 操作数1,操作数2
CMP指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行比较,同时更新CPSR中条件标志位的值。该指令进行一次减法运算,但不存储结果,只 更改条件标志位。 标志位表示的是操作数1与操作数2的关系(大、小、相等),例如,当操作数1大于操作操作数2,则此后的有GT后缀的指令将可以执行。
指令示例:
CMP R1,R0 ;将寄存器R1的值与寄存器R0的值相减,并根据 结果设置CPSR的标志位
CMP R1,#100 ;将寄存器R1的值与立即数100相减,并根 据结果设置CPSR的标志位
4、TST指令(测试)
TST指令的格式为:
TST{条件} 操作数1,操作数2
TST指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的与运算,并根据运算结果更新CPSR中条件标志位的值。操作数1是要测试的数 据,而操作数2是一个位掩码,该指令一般用来检测是否设置了特定的位。
指令示例:
TST R1,#%1 ; 用于测试在寄存器R1中是否设置了最低位
(%表 示二进制数)
TST R1,#0xffe ;将寄存器R1的值与立即数0xffe按位与,并根据
结果设置CPSR的标志位
5、ADD指令(相加)
ADD指令的格式为:
ADD{条件}{S} 目的寄存器,操作数1,操作数2
ADD指令用于把两个操作数相加,并将结果存放到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。
指令示例:
ADD R0,R1,R2 ; R0 = R1 + R2
ADD R0,R1,#256 ; R0 = R1 + 256
ADD R0,R2,R3,LSL#1 ; R0 = R2 + (R3 << 1)
6、ADC指令(带进位相加)
ADC指令的格式为:
ADC{条件}{S} 目的寄存器,操作数1,操作数2
ADC指令用于把两个操作数相加,再加上CPSR中的C条件标志位的值,并将结果存放到目的寄存器中。它使用一个进位标志位,这样就可以做比32位大的数 的加法,注意不要忘记设置S后缀来更改进位标志。操作数1应是一个寄存器,操作数2可以是一 个寄存器,被移位的寄存器,或一个立即数。
以下指令序列完成两个128位数的加法,第一个数由高到低存放在寄存器R7~R4,第二个数由高到低存放在寄存器R11~R8,运算结果由高到低存放在寄 存器R3~R0:
ADDS R0,R4,R8 ; 加低端的字
ADCS R1,R5,R9 ; 加第二个字,带进位
ADCS R2,R6,R10 ; 加第三个字,带进位
ADC R3,R7,R11 ; 加第四个字,带进位
7、SUB指令(相减)
SUB指令的格式为:
SUB{条件}{S} 目的寄存器,操作数1,操作数2
SUB指令用于把操作数1减去操作数2,并将结果存放到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即 数。该指令可用于有符号数或无符号数的减法运算。
指令示例:
SUB R0,R1,R2 ; R0 = R1 - R2
SUB R0,R1,#256 ; R0 = R1 - 256
SUB R0,R2,R3,LSL#1 ; R0 = R2 - (R3 << 1)
8、RSC指令(反向带进位减)
RSC指令的格式为:
RSC{条件}{S} 目的寄存器,操作数1,操作数2
RSC指令用于把 操作数2减去操作数1,再减去CPSR中的C条件标志位的反码,并将结果存放到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位 的寄存器,或一个立即数。该指令使用进位标志来表示借位,这样就可以做大于32位的减法,注意不要忘记设置S后缀来更改进位标志。该指令可用于有符号数或 无符号数的减法运算。
指令示例:
RSC R0,R1,R2 ;R0 = R2 – R1 - !C
9、AND指令(逻辑位 与)
AND指令的格式为:
AND{条件}{S} 目的寄存器,操作数1,操作数2
AND指令用于在两个操作数上进行逻辑与运算,并把结果放置到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个 立即数。该指令常用于屏蔽操作数1的某些位。
指令示例:
AND R0,R0,#3 ;该指令保持R0的0、1位,其余位清零。
10、ORR指令(逻辑位 或)
ORR指令的格式为:
ORR{条件}{S} 目的寄存器,操作数1,操作数2
ORR指令用于在两个操作数上进行逻辑或运算,并把结果放置到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个 立即数。该指令常用于设置操作数1的某些位。
指令示例:
ORR R0,R0,#3 ;该指令设置R0的0、1位,其余位保持不变。
11、EOR指令(逻辑位 异或)
EOR指令的格式为:
EOR{条件}{S} 目的寄存器,操作数1,操作数2
EOR指令用于在两个操作数上进行逻辑异或运算,并把结果放置到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一 个立即数。该指令常用于反转操作数1的某些位。
指令示例:
EOR R0,R0,#3 ;该指令反转R0的0、1位,其余位保持不变。
12、BIC指令(位清零)
BIC指令的格式为:
BIC{条件}{S} 目的寄存器,操作数1,操作数2
BIC指令用于清除操作数1的某些位,并把结果放置到目的寄存器中。操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。 操作数2为32位的掩码,如果在掩码中设置了某一位,则清除这一位。未设置的掩码位保持不 变。
指令示例:
BIC R0,R0,#%1011 ;该指令清除R0中的位 0、1、和 3,其余的位保持不变。