CPSR:程序状态寄存器(current program status register) cpsr在用户级编程时用于存储条件码
SPSR(备份程序状态寄存器)
在异常中断退出时,可以用SPSR来恢复CPSR。由于用户模式和系统模式不是异常
ARM处理器共有37个寄存器,被分为若干个组(BANK):
31个通用寄存器
6个状态寄存器(目前只使用了其中的一部分)
ARM处理器有7种不同的处理器模式,每一种处理器模式下都有一组相应的寄存器与之对应。
MMU是Memory Management Unit的缩写,中文名是内存管理单元,它是中央处理器(CPU)中用来管理虚拟存储器、物理存储器的控制线路,同时也负责虚拟地址映射为物理地址,以及提供硬件机制的内存访问授权。
MIPS
Million Instructions Per Second的缩写,每秒处理的百万级的机器语言指令数。这是衡量CPU速度的一个指标。像是一个Intel 80386 电脑可以每秒处理3百万到5百万机器语言指令,即我们可以说80386是3到5MIPS的CPU。MIPS只是衡量CPU性能的指标。
ARM体系结构将存储器看作是从零地址开始的字节的线性组合。 从1字节到3字节放置第一个存储的字数据,4到7放一个······。(4个字节一个字)
两种方法存储数据:
大端格式: 字数据的高字节存储在低地址中,字数据的低字节存储在高地址中。
( 地对空,空对地 头大)
小端格式: 和大端相反。
字需要4字节对齐(地址的低两位为0)
ARM微处理器的运行模式可以通过软件改变,也可通过外部中断或异常处理改变。
在任何时候,通用寄存器R14~R0,程序计数器PC(r15),一个或两个状态寄存器都是可访问的。
未分组寄存器RO~R7:
在所有的运行模式下,未分组寄存器都指向同一个屋里寄存器,他们未被系统用作特殊的用途。
分组寄存器R8~R14:
对于R8~R12来说,每个寄存器对应两个不同的物理寄存器:fiq模式时,访问寄存器R8_fiq~R12_fiq:使用非fiq模式时,访问寄存器 R8_usr~R12_usr。
对于R13~R14来说,每个寄存器对应6个不同的物理寄存器,其中一个是用户模式与系统模式共用。
R13在ARM指令中常用作堆栈指针。
R14也称作子程序连接寄存器(Subroutine Link Register) 或 连接寄存器LR。:存储子程序的返回地址
当执行BL子程序调用指令时,R14中得到R15的备份。其他情况下,R14用作通用寄存器。
在每一种运行模式下,都可以用R14保存子程序的返回地址,当用BL或BLX指令调用子程序时,将PC的当前值拷贝给R14,执行完子程序后,又将R14的值拷贝回PC,即可完成子程序的调用返回。
R15 PC 程序计数器
寄存器R15用作程序计数器。在ARM状态下,位[31:2]用于保存PC;
【为了保证程序(在操作系统中理解为进程)能够连续地执行下去,CPU必须具有某些手段来确定下一条指令
的地址。而程序计数器正是起到这种作用,所以通常又称为指令计数器。在程序开始执行前,必须将它的起始
地址,即程序的一条指令所在的内存单元地址送入PC,因此程序计数器(PC)的内容即是从内存提取的第一条
指令的地址。当执行指令时,CPU将自动修改PC的内容,即每执行一条指令PC增加一个量,这个量等于指令所
含的字节数,以便使其保持的总是将要执行的下一条指令的地址。由于大多数指令都是按顺序来执行的,所以
修改的过程通常只是简单的对PC加1。当程序转移时,转移指令执行的最终结果就是要改变PC的值,此PC值就
是转去的地址,以此实现转移。有些机器中也称PC为指令指针IP(Instruction Pointer)。】
由于ARM体系结构采用了多级流水线技术,对于ARM指令集来说,PC总是指向当前指令的下两条指令的地址,即PC的值为当前指令的地址值加8个字节。
R16
寄存器R16用作CPSR,CPSR可以在任何运行模式下被访问,它包括:条件标志位,中断禁止位,当前处理器模式标志位,以及其他一些相关的控制和状态位。
由于用户模式和系统模式不属于异常模式,他们没有SPSR,当在这两种模式下访问SPSR,结果是未知的。
异常 Exceptions :当正常的程序执行流程发生暂时的停止时,称之为异常。
对异常的响应: 当一个异常出现以后,ARM微处理器会执行以下几步操作------
1·将下一条指令的地址存入相应的连接寄存器LR,以便程序在处理异常返回时能从正确的位置重新开始执行。
2·将CPSR复制到相应的SPSR中。 (前两步存)
3·根据异常类型,强制设置CPSR的运行模式位。
4·强制PC从相关的异常向量地址取下一条指令执行,从而跳转到相应的异常处理程序 (后两步改)
从异常返回:
1·将连接寄存器LR的值减去相应的偏移量(执行异常处理程序时,PC加的数)后送到PC中。
2·将SPSR复制会CPSR中。
3·若在进入异常处理时设置了中断禁止位,要在此清除。
可以认为应用程序总是从复位异常处理程序开始执行,因此复位异常处理程序不需要返回。
应用程序中的异常处理:
当系统运行时,异常可能会随时发生,为保证在ARM处理器发生异常时不至于处于未知状态,在应用程序的设计中,首先要进行异常处理,采用的方式是在异常向量表中的特定位置放置一条跳转指令,跳转到异常处理程序,当ARM处理器发生异常时,程序计数器PC就会被强制设置为对应的异常向量,从而跳转到异常处理程序,当异常处理完成以后,返回到主程序继续执行。
==================================================================
ARM处理器的指令集是 加载/存储 型的,即:指令集仅能处理寄存器中的数据,而且处理结果都要放回寄存器中,而对系统存储器的访问则需要通过专门的 加载/存储 指令来完成。
每一条ARM指令包括4位的条件吗,位于指令的最高4位[31:28]。条件码共有16种,每种条件码可用两个字符(字母)表示,这两个字符可以添加在指令的后面和指令同时使用。
寻址方式:就是处理器根据指令中给出的地址信息来寻找物理地址的方式。
1·立即数寻址:操作数本身就在指令中给出,只要取出指令也就取到了操作数。
2·寄存器寻址:利用寄存器中的数值作为操作数。
3·寄存器间接寻址:以寄存器中的值作为操作数的地址,而操作数本身存放在存储器中。
4·基址变址寻址:将寄存器的内容与指令中给出的地址偏移量相加==>得到一个操作数的有效地址。
5·多寄存器寻址:一条指令可以完成多个寄存器值的传送。
6·相对寻址:以程序计数器PC的当前值为基地址,指令中的地址标号作为偏移量,将两者相加之后得到操作数的有效地址。
7·堆栈寻址:只用一个称作堆栈指针的专用寄存器指示当前的操作数位置,堆栈指针总是指向栈顶。
==========================================================================
跳转指令:用于实现程序流程的跳转,在ARM程序中有两种方法可以实现程序流程的跳转:
=== 使用专门的跳转指令
=== 直接向程序计数器PC写入跳转地址值
ARM指令集中的跳转指令可以完成从当前指令向前或向后的32MB的地址空间的跳转,包括以下4条指令:
1· B 跳转指令
2· BL 带返回的跳转指令
3· BLX 带返回和状态切换的跳转指令
4· BX 带状态切换的跳转指令
B 注意:储存在跳转指令中的实际值是相对当前PC值的一个偏移量,而不是一个绝对地址。它的值由汇编器来计算。
B Lable //程序无条件跳转到标号Lable处执行
BL :在跳转之前,会在寄存器R14中保存PC的当前内容,因此,可以通过将R14的内容重新加载到PC中,来返回到跳转指令之后的那个指令处执行。
BL Lable :跳转的同时将当前的PC值保存到R14中
BX :目标地址处的指令可以是ARM指令,也可以是Thumb指令。
====================================================================
数据处理指令:
1· 数据传送指令用于在寄存器和存储器之间进行数据的双向传输。
2· 算术逻辑运算指令不但将运算结果保存在目的寄存器中,同时更新CPSR中的相应条件标志位。
3· 比较指令不保存运算结果,只更新CPSR中相应的条件标志位。
MOV PC, R14 :将寄存器R14的值传送到PC,常用于子程序返回
MOV R1, R0, LSL#3 :将R0的值左移3位后送到R1
CMP 用于吧一个register的内容和另一个register的内容 或 立即数进行比较,同时更新CPSR中的条件标志位的值。
CMP R1, #100 :将register R1的值与立即数100相减,并根据结果设置CPSR的标志位
TST 用于把一个register的内容和另一个register的内容或立即数进行安位的 与 运算,并根据运算结果更新CPSR中的条件位的值。
TST R1, #%1 : 用于测试register R1中是否设置了最低位(%表示二进制数)
TEQ 相等测试
ADD R0, R2, R3, LSL#1 : R0 = R2 + (R3 << 1)
ADC :把两个操作数相加,再加上CPSR中的C条件标记为的值,并将结果存放到目的register中,它使用一个进位标志位,这样就可以做比32位大的数的加法, 注意:不要忘记设置S后缀来更改进位标志。
SUB :用于两个操作数相减,并将结果存放到目的寄存器中
SUB R0, R1, R2 :R0 = R1 - R2
AND
AND R0, R0, #3 :该指令保存R0的0,1位,其余位清零。
ORR R0, R0, #3 :设置R0的0,1位,其余位保存不变。
BIC R0, R0, #%1011 :清除R0中的位0,1,3,其余位保持不变。
MULS R0, R1, R2 :R0 = R1 × R2 ,同时设置CPSR中的相关条件标志位
MLA 乘加指令
MLA RO, R1, R2, R3 :R0 = R1 × R2 + R3
==========================================================================
程序状态寄存器访问指令
用于在程序状态寄存器和通用寄存器之间传送数据
1· MSR 程序 状态寄存器 获得 通用寄存器 的数据传送指令;
2· MRS 通用寄存器 获得 状态寄存器
MRS 指令一般用在以下几种情况:
-- 当需要改变程序状态寄存器的内容时。
-- 当在异常处理或进程切换时,需要保存程序状态寄存器的值,可用该指令读出程序状态寄存器的值,然后保存。
MRS R0, CPSR :传送CPSR的内容到R0
MRS R0, SPSR :传送SPSR的内容到R0
MSR CPSR_c, R0 :传送R0的内容到CPSR,但仅仅修改CPSR中的控制位域
======================================================================
加载/存储指令
加载:将存储器中的数据传送到寄存器
存储:将寄存器中的数据存储到存储器
LDR 字数据加载指令
LDRB 字节数据加载指令
STR 字数据存储指令
STRB 字节数据存储指令
LDR R0, [R1] :将存储器地址为R1的字数据读入寄存器R0
LDR R0, [R1, #8] :将存储器地址为R1+8 的字数据读入寄存器R0
LDR R0, [R1, R2]! :将存储器地址为R1+R2的字数据读入寄存器R0,并将新地址R1+R2写入R1
LDR R0, [R1], R2 :将存储器地址为R1的字数据读入寄存器R0, 并将新地址R1+R2写入R1
STR R0,[R1],#8 :将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1
STR R0,[R1,#8] : 将R0中的字数据写入以R1+8为地址的存储器中。
+++++++++++++++++++++++++++++++++++++
批量数据加载/存储指令: 可以一次在一片连续的存储器单元和多个寄存器之间传送数据。
(ARM应用系统开发详解 第35页)
============================================================================
数据交换指令:能在寄存器和存储器之间交换数据。
SWP 字数据交换指令
SWPB 字节数据交换指令
SWP R0, R1, [R2] :将R2所指向的存储器中的字数据传送到R0,同时将R1中的字数据传送到R2
所指向的存储单元。
SWP RO, RO, [R1] :R0 和 R1指向内存中的数据 的交换
===========================================================================
移位指令
LSL 逻辑左移
ASL 算术左移(和逻辑左移是等价的,可以自由互换)
LSR 逻辑右移
ASR 算术右移
ROR 循环右移
RRX 带扩展的循环右移
MOV R0, R1, LSR#2 :将R1中的内容右移两位后传送到R0中,左端用零来填充。
MOV R0, R1, ASR#2 :将R1中的内容右移两位后传送到R0中,左端用第31位的值累填充(即最高位值不变)。
============================================================================
协处理器 coprocessor
一种芯片,用于减轻系统微处理器的特定处理任务。例如,数学协处理器可以控制数字处理;图形协处理器可以处理视频绘制。例如,intel pentium 微处理器就包括内置的数学协处理器。
协处理器可以附属于ARM处理器。一个协处理器通过扩展指令集或提供配置寄存器来扩展内核处理功能。一个或多个协处理器可以通过协处理器接口与ARM内核相连。
协处理器可以通过一组专门的、提供load-store类型接口的ARM指令来访问。
协处理器指令:在程序执行的过程中,每个协处理器只执行针对自身的协处理指令,忽略ARM处理器和其他协处理器的指令。
主要用于: ARM处理器初始化ARM协处理器的数据处理操作 & 在ARM处理器的寄存器和协处理器的寄存器之间传送数据,和在ARM协处理器的寄存器和存储器之间传送数据。
=============================================================================
符号定义(Symbol Definition )伪指令
GBLA 用于定义一个全局的数字变量,并初始化为0;
GBLL 用于定义一个全局的逻辑变量,并初始化为F(假);
GBLS 用于定义一个全局的字符串变量,并初始化为空;
GBLA Test1
Test1 SETA 0xaa :定义一个全局的数字变量,名为Test1,将该变量赋值为0xaa
GBLL Test2
Test2 SETL {TRUE} :定义一个全局的逻辑变量,名为Test2 将该变量赋值为真
GBLS Test3
Test3 SETS "Testing" :将该变量赋值为“Testing“
LCLA , LCLL , LCLS 用于定义一个ARM程序中的局部变量,并将其初始化。
RLIST :对一个通用寄存器列表定义名称,使用该伪指令定义的名称,使用该伪指令定义的名称可在ARM指令LDM/STM 中使用。在LDM/STM指令中,列表中的寄存器访问次序为根据寄存器的编号由低到高,而与列表中的寄存器排列次序无关。
RegList RLIST {R0-R5, R8, R10} :将寄存器列表名称定义为RegList,可在ARM指令LDM/STM中通过该名称访问寄存器列表。
==============================================================================
Data Definition 数据定义伪指令
:一般用于为特定的数据分配内存单元,同时可以完成已分配单元的初始化。
Str DCD “This is a test!" ;Str是一个连续的字节存储单元并用This is a test初始化。
DCB也可以用 “=”代替。
SPACE:用于分配一片连续的存储区域并初始化为0. SPACE也可用‘%’代替。
DataSpace SPACE 100 : 分配连续100字节的存储单元并初始化为0.
=======================================================================
在ARM汇编语言程序中,子程序的调用一般是通过BL指令来实现的。在程序中,使用指令:
BL 子程序名
即可完成子程序的调用。
========================================================================
汇编语言与C/C++的混合编程
在一个完成的程序设计中,除了初始化部分用汇编语言完成以外,其主要的编程任务一般都用C/C++完成。