1、一、二进制1.1 莱布尼茨发明了二进制,并初步判断了二进制可以用于计算。布尔提出了布尔代数,说明了二进制的运算规则,可以用来进行任何计算。1.2 在数字电路这门课程中,可以看到,使用电子器件很容易实现二进制及其运算。二、对计算机的认识2.1 计算机,实际是一种自动化计算装置,其历史悠久。2.2 现代计算机,是冯.诺依曼在前人经验上提出的。他将计算机划分为五个组成部分:运算器、控制器、存储器、输入设备、输出设备。运算器和控制器组成了 CPU。这种组成结构,被称为冯.诺依曼体系结构。其关键为:2.2.1 程序存放在存储器2.2.2 控制器起着全局控制管理作用。2.2.3 从存储器中,取出一条指令,
2、送到运算器中进行处理。周而复始,直到最后一条指令执行完毕。三、对 CPU的认识3.1 CPU 内部包括了许多部件,比较重要的有 ALU、CU、流水线、缓存、片内总线、ICE、寄存器。这些部件,有些是程序员在工作中所特别关心的(称之为可见的、不透明的) 。3.2 对于绝大多数程序员来说,主要关心的是寄存器及其功能作用。对于系统程序员来说,他们还要关心 MMU,cache,TCM。3.3 不同体系结构的 CPU,寄存器的类型与作用有所不同。3.4 对于 ARM CPU 来说,寄存器分为:通用寄存器、状态与控制寄存器(程序状态寄存器) 、指令指针寄存器(程序计数器) 。3.5 ARM CPU 共有
3、37 个寄存器(32 位):31 个通用寄存器,6 个状态寄存器。3.6 通用寄存器的作用:存放数据。这个数据,分为两种类型:第一种是直接进行算术逻辑运算的数据;第二种,是数据在存储器的位置或地址(在 C 语言中,又叫做指针) 。3.7 状态与控制寄存器(程序状态寄存器)的作用:当 CPU 进行一次计算后,得到一个结果。这个结果对 CPU 后续的运行有影响。因此,状态与控制寄存器就必须把影响给记录下来。3.8 指令指针寄存器(程序计数器)的作用:下一条要运行的指令在存储器的位置(地址) 。3.9 ARM CPU 可以工作在 7 种工作模式之一:用户、系统、管理、中止、未定义、中断、快中断。管理
4、、中止、未定义、中断、快中断这 5 种合称为异常模式。除了用户模式以外,其它 6 种模式合称为特权模式。将 CPU 的工作模式进行细分,是为了保护系统的安全性,提高系统的性能。3.10 R0R7、R15,是 7 个工作模式所共用的。3.11 R8R12,有 2 套,快中断使用 1 套,其它 6 个工作模式共用 1 套。3.12 R13R14,共有 6 套,用户模式和系统模式共用 1 套,其它每个工作模式分别使用1 套。3.13 CPSR,只有 1 个,由所有的工作模式所共用。3.14 SPSR,有 5 个,管理、中止、未定义、中断、快中断这 5 个工作模式各自有 1 个。3.15 子程序间通过
5、寄存器 R0R3 来传递参数。这时,寄存器 R0R3 可记作 a0a3 。3.16 在子程序中,使用寄存器 R4R11 来保存局部变量。这时,寄存器 R4R11 可以记作 v1 v8。3.17 寄存器 R12 用作过程调用中间临时寄存器,记作 IP。3.18 寄存器 R13 用作堆栈指针,记作 SP。3.19 寄存器 R14 称为连接寄存器,记作 LR。它用于保存子程序的返回地址。3.20 寄存器 R15 是程序计数器,记作 PC。四、对存储器的认识4.1 在冯. 诺依曼体系结构中,程序和数据是存放在存储器中的。4.2 这个存储器就是我们常说的内存。4.3 在物理上,如果把程序和数据分别放在不
6、同的存储器中,那么得到哈佛结构。4.4 由于计算机只能处理二进制,因此存放在存储器中的程序和数据都是以二进制形式存在的。4.5 在计算机组成原理中,我们知道,存储器与 CPU 是通过总线连接起来的。而且,存储器本身有很多的组合方式。4.6 不过,对于程序员来说,在绝大多数场合中,我们都认为存储器的基本单位是 1 个字节(8 bit) ,或称为一个 存储单元。4.7 存储单元可以比做房间,存储单元里面的内容就是房间里面的人。4.8 现在,对于每个存储单元,分别给一个编号(类似于房间号码) 。这个编号,我们称之为地址(在语言中,又称为指针) 。4.9 编号的范围,不同的 CPU 有不同的规定。4.
7、10 对于 32 位 ARM CPU,编号范围为 0 到 232-1。这个范围称为地址空间。显然,这个空间是一维的线性空间。4.11 连接存储器与 CPU 的硬件线路分为:数据总线、地址总线、控制总线。4.12 我们说一个 ARM CPU 是 32 位的,那么数据总线共 32 根。一次可以读取 32bit 数据,即 4 个字节。当然,也可以只读取 1 个字节,2 个字节(半字) 。4.13 不管是冯.诺依曼体系结构还是哈佛结构,程序和数据的地址都是处于同一个地址空间。五、对外设的认识5.1 CPU 的速度远远大于外设的速度。5.2 外设的种类非常多:按传输的数值类型来划分,可以分为模拟量和数字
8、量;按一次传输数据的数量来划分,可以分为串行和并行;按对总线的占用方式来划分,可以划分为独占式(点对点式)和共享式。5.3 为了保证兼容性、通用性、速度匹配,在 CPU 和外设之间专门设置一种电路部件,这种电路部件被称为接口电路。简称为接口。5.4 通过接口,实现 CPU 与外设之间的数据传输,对外设进行控制,检测外设的状态。5.5 跟存储器一样,每个接口都有一个编号。同样地,这个编号被称为地址(接口地址) 。5.6 与存储器的存储单元的编号一样,全部的接口编号也形成一个地址空间。5.7 如果存储器的地址空间与接口的地址空间是独立的,那么,所得到的地址编址方案叫做独立编址。5.8 如果把存储器
9、的地址空间与接口的地址空间整合在一起,那么,所得到的地址编址方案叫做统一编址。5.9 ARM CPU 采用了统一编址方案。六、ARM CPU指令的认识6.1 ARM CPU 有两大类指令,一个就叫做 ARM 指令集,另一种叫做 Thumb 指令集。6.2 我们主要学习 ARM 指令集。6.3 ARM CPU 是一种 RISC CPU,一条 ARM 指令占用了 4 个字节,即 32bit。6.4 ARM 指令的汇编语言格式为: S ,6.4.1 R39.4 CPSR 与 SPSRN M 1 M 0M 3 M 2T M 4I FZ C V QD N M ( R A Z )012345672 62
10、72 82 93 03 1 8条件码标志D S P 指令运算结果出现饱和或者溢出控制标志位F = 1标志运行T h u m b指令集D N M ( D o N o t M o d i f y )位 , 将来扩展预留位 ; 初始化时为零 。R A Z ( A p p e a r a s Z e r o w h e n R e a d ) 。I = 1普通中断关闭F = 1快速中断关闭十、关于 ARM的指令10.1 ARM 指令集大致分为 6 类:分支指令、Load/Store 指令、数据处理指令、程序状态寄存器指令、异常中断指令、协处理器指令。10.2 分支指令。ARM 有两种方法可以实现程序分
11、支转移。 跳转指令。 长跳转。直接向 PC 寄存器( R15)中写入目标地址。10.2.1 跳转指令有 4 种:B、BL、BX、BLX。10.2.2 B 分支指令,语法:Bcond label10.2.3 BL 带链接分支指令,语法: BLcond label10.2.4 BX 分支并可选地交换指令集,语法: BXcond Rm10.2.5 BLX 带链接分支并可选择地交换指令集,语法:BLXcond label | Rm10.2.6 BL 指令的意义:Branch and Link。例如: bl MyPro ;调用子程序 MyProMyPro ;子程序 MyPro 本体 mov PC, LR
12、 ;将 R14 的值送入 R15,返回10.2.7 BX 指令使用举例。通过使用 BX 指令可以让 ARM 处理器内核工作状态在 ARM 状态和 Thumb 状态之间进行切换。;从 ARM 状态转变为 Thumb 状态LDR R0, =Sub_Routine+1BX R0;从 Thumb 状态转变为 ARM 状态LDR R0, =Sub_RoutineBX R010.2.8 长跳转。直接向 PC 寄存器写入目标地址值,可以实现 4GB 地址空间中的任意跳转。例如,以下的两条指令实现了 4GB 地址空间中的子程序调用:MOV LR, PC;保存返回地址MOV R15, #0x00110000;无
13、条件转向绝对地址 0x110000;此 32 位立即数地址应满足单字节循环右移偶数次10.3 Load/Store 指令,又称为数据加载与存储指令。 用于在存储器和处理器之间传输数据。Load 用于把内存中的数据装载到寄存器,Store 指令用于把寄存器中的数据存入内存。 同时,由于 ARM CPU 采用统一编址,因此,外围 I/O 也使用 Load/Store 指令。10.3.1 共有 3 种类型的 Load/Store 指令: 单寄存器传输指令 多寄存器传输指令 交换指令10.3.2 Load/Store 指令变址模式。变址模式有四种:零偏移、前变址、后变址、回写前变址。显然,变址的作用等
14、效于 C 语言中的指针。变址模式 数据 基址寄存器 指令举例零偏移 membase 直接基址寄存器寻址LDR r0, r1回写前变址 membase+offset 基址寄存器加偏移量LDR r0, r1, #4!前变址 membase+offset 不变 LDR r0, r1, #4后变址 membase 基址寄存器加偏移量LDR r0, r1, #410.3.3 单寄存器传送指令助记码 操作 指令描述LDR 把一个字装入一个寄存器 Rdmem32addressSTR 从一个寄存器保存一个字 Rdmem32addressLDRB 把一个字节装入一个寄存器 Rdmem8addressSTRB 从
15、一个寄存器保存一个字节 Rdmem8addressLDRH 把一个半字装入一个寄存器 Rdmem16addressSTRH 从一个寄存器保存一个半字 Rdmem16addressLDRSB 把一个有符号字节装入寄存器 Rd符号扩展(mem8address)LDRSH 把一个有符号半字装入寄存器 Rd符号扩展(mem16address)10.3.4 单寄存器传送指令,以 LDR和 STR为例LDR R2,R3 ,#0x0C读取 R3 0x0C 地址上的一个字数据内容,放入 R2。属前变址。STR R1,R0 ,#4!R04R1 ,R0=R04符号“!” 表明指令在完成数据传送后应该更新基址寄存器
16、;属回写前变址。LDR R1,R0 ,R3 ,LSL #1将 R0R32 地址上的存储单元的内容读出,存入 R1。LDR R3, STARTSTART 代表着子程序的偏移地址。ARM CPU 自动将偏移地址与程序计数器PC 的值进行相加。PC ,是隐含的基址寄存器,代表着当前正在执行的指令。10.3.5 多寄存器传输指令。前面第七部分的多寄存器寻址方式已经讲过了。10.3.6 交换指令。SWP,可以一次性地完成数据交换。10.4 数据处理指令10.4.1 数据处理指令对存放在寄存器中的数据进行操作,分为:数据传送指令、算术指令、逻辑指令、比较指令和乘法指令。10.4.2 算术指令和逻辑运算指令
17、完成常用的算法与逻辑运算,将运算结果保存于目的寄存器中,同时更新 CPSR 的相应条件标志位。10.4.3 比较指令不保存运算结果,只更新 CPSR 中相应的条件标志位。10.4.4 ARM 数据处理指令机器编码格式如下图所示:11.4.4.1 cond: 指令执行的条件码。跟上一条指令有关。11.4.4.2 I:用于区别第二操作数据是立即数( I=1)还是寄存器移位(I=0)11.4.4.3 opcode:数据处理指令操作码。11.4.4.4 S:用于设置条件码, S=0,条件码不改变,S=1,条件码根据具体指令的结果修改。11.4.4.5 Rn:第一操作数寄存器。11.4.4.6 Rd:目
18、标寄存器。11.4.4.7 operand2:第二操作数,该数可以是立即数或寄存器移位数。10.4.5 数据传送指令11.4.5.1 将一个寄存器中的数据传送到另一个寄存器,或者将一个立即数传送到寄存器。11.4.5.2 通常用来设置寄存器的初始值。11.4.5.3 数据传送指令包括: MOV 数据传送指令 MVN 数据取反传送指令11.4.5.4 实例:10.4.6 移位操作10.4.6.1 ARM微处理器一个显著的特征是:在操作数进入 ALU之前,对操作数进行预处理。10.4.6.2 如:指定位数的左移或右移,这种功能明显增加了数据处理操作的灵活性。10.4.6.3 移动操作包括:LSL
19、逻辑左移LSR 逻辑右移ASR 算术右移ROR 循环右移RRX 带扩展的循环右移10.4.6.4 例:设指令操作之前,R0=0x00000000, R1=0x80000004,则执行如下指令后 R0, R1的值有什么变化?MOV R0, R1, LSL #1分析:该指令的作用是将 R1 中的内容左移一位后传送到 R0 中。指令执行时,首先实现 R1, LSL #1,即将 R1 的内容左移一位,得到 8。然后该值送入R0,故 R0 中的值为 0x00000008,R0 中原来的值被覆盖掉,R1 的值仍为0x80000004。10.4.7 算术指令10.4.7.1 主要是加法和减法。10.4.7.
20、2 两个 32位数据的加减操作。10.4.7.3 与第二操作数结合起来,更加灵活。10.4.7.4 主要包括:ADD 加法指令ADC 带进位加法指令SUB 减法指令SBC 带借位减法指令RSB 逆向减法指令RSC 带借位的逆向减法指令10.4.7.5 以 ADD为例: 汇编格式:ADD S Rd, Rn, operand2 寄存器 Rn 的值和操作数 operand2 相加,结果送 Rd 寄存器,即Rd=Rn+operand2。 Rd 为操作数 1,要求是一个寄存器。 operand2 是操作数 2,可以是一个寄存器,被移位的寄存器或一个立即数。 S 选项影响 CPSR 中条件标志位的值: N
21、、Z、C 、V 标志。 示例:10.4.8 逻辑运算指令10.4.8.1 对操作数进行按位操作。10.4.8.2 位与位之间无进位或借位。10.4.8.3 没有数的正负与数的大小之分。10.4.8.4 主要包括:10.4.8.5 以 AND指令为例:10.4.9 比较指令10.4.9.1 将一个寄存器与一个 32位的值进行比较或测试。10.4.9.2 根据结果更新 CPSR中的标志位,但不影响其他的寄存器。10.4.9.3 在设置标志位后,其他指令可以通过条件执行来改变程序的执行顺序。10.4.9.4 对于比较指令,不需要使用 S后缀就可以改变标志位的值。10.4.9.5 比较指令包括: CM
22、P 比较指令。 CMN 反值比较指令。 TST 位测试指令。 TEQ 相等测试指令。10.4.9.6 以 CMP为例: CMP 指令将寄存器 Rn 的内容和另一个操作数 operand2 进行比较,同时更新 CPSR 中条件标志位的值。 该指令实质上是进行一次减法运算,但不存储结果,只更改条件标志位。后面的指令就可以根据条件标志位来决定是否执行。10.4.10乘法指令10.4.10.1 把一对寄存器的内容相乘,然后根据指令类型把结果累加到其他的寄存器。10.4.10.2 乘法指令与乘加指令共有 6条,根据运算结果可分为 32位运算和 64位运算两类。10.4.10.3 64位乘法又称为长整型乘
23、法指令,由于结果太大,不能再放在一个 32位的寄存器中,所以把结果存放在 2个 32位的寄存器 Rdlo和 Rdhi中。10.4.10.4 Rdlo存放结果的低 32位,Rdhi 存放结果的高 32位。10.4.10.5 对于乘法指令,所有源操作数、目的寄存器都必须为通用寄存器,不能对操作数使用立即数或被移位的寄存器。10.4.10.6 目的寄存器 Rd和操作数 Rm必须是不同的寄存器。10.4.10.7 乘法指令与乘加指令共有以下 6条: MUL 32位乘法指令。 MLA 32位乘加指令。 SMULL 64位有符号数乘法指令。 SMLAL 64位有符号数乘加指令。 UMULL 64位无符号数
24、乘法指令。 UMLAL 64位无符号数乘加指令。10.4.10.8 以 MUL为例: 将操作数 Rm与操作数 Rs的乘法运算,并把结果放置到目的寄存器 Rd中。即Rd=RmRs。 S选项决定指令的操作是否影响 CPSR中条件标志位的值,有 S时指令执行后的结果影响 CPSR中条件标志位 N和 Z值。 在 ARMv4及以前版本中,标志 C和 V不可靠,在 ARMv5及以后版本中不影响C和 V标志(其它的乘法指令对于 S的规定与此相同) 。10.4.11异常中断指令 SWI10.4.11.1 在 ARM 体系结构中,存在 7 种异常处理。10.4.11.2 当某种异常发生时,CPU 把程序计数器
25、PC 设置为一个特定的存储器地址,这个地址存放了一条跳转指令。CPU 执行这条跳转指令,就可以进入相应的中断处理服务程序的起始地址(入口) ,对异常进行处理。10.4.11.3 这 7 个异常所对应的存储器地址形成了一张表,即向量表(vector table) 。10.4.11.4 向量表在 ARM 地址空间的位置,有两种情况,根据具体的 CPU 来确定,如下表所示:异 常 类 型 处理器模式 执行低地址 执行高地址复位异常(Reset) 特权模式 0x00000000 0xFFFF0000未定义指令异常(Undefined Interrupt) 未定义指令中止模式 0x00000004 0x
26、FFFF0004软中断异常(SWI) 特权模式 0x00000008 0xFFFF0008预取异常(Prefetch Abort) 数据访问中止模式 0x0000000C 0xFFFF000C数据异常(Data Abort) 数据访问中止模式 0x00000010 0xFFFF0010外部中断异常(IRQ) 外部中断请求模式 0x00000018 0xFFFF0018快速中断异常(FIQ) 快速中断请求模式 0x0000001C 0xFFFF001C10.4.11.5 当异常发生时,分组寄存器 r14 和 SPSR 用于保存处理器状态,操作伪指令如下:R14_ = return link SP
27、SR_ = CPSR CPSR40 = exception mode number CPSR5 = 0 /*进入 ARM 状态*/ If = = reset or FIQ then CPSR6 = 1 /*屏蔽快速中断 FIQ*/ CPSR7 = 1 /*屏蔽外部中断 IRQ*/ PC = exception vector address 10.4.11.6 异常返回时,SPSR 内容恢复到 CPSR,连接寄存器 r14 的内容恢复到程序计数器 PC。10.4.11.7 这里,专注于软中断异常 SWI。软中断异常是程序员调用 SWI 指令所引起的异常。10.4.11.8 软中断异常发生时,处理
28、器进入特权模式,执行一些特权模式下的操作系统功能。10.4.11.9 软中断异常发生时,处理器执行下列伪操作。r14_svc = address of next instruction after the SWI instruction SPSR_und = CPSR CPSR40 = 0b10011 /*进入特权模式*/ CPSR5 = 0 /*处理器进入 ARM 状态*/ /*CPSR6保持不变*/ CPSR7 = 1 /*禁止外设中断 */ If high vectors configured then PC = 0xffff0008 Else PC = 0x0000000810.4.1
29、1.10 为什么要设计 SWI 呢?原因有很多,例如:CPU 可以从用户模式转移到系统模式;可以方便程序员扩充系统功能,等等。10.4.11.11 软中断异常 SWI 还可以进一步包含成多个特定功能。每个功能用 SWI 中断号进行区分。10.4.11.12 所以,当发生 SWI 异常,进入异常处理程序时,异常处理程序必须提取 SWI 中断号,从而得到用户请求的特定 SWI 功能。10.4.11.13 SWI 指令格式SWIcond immed_2410.4.11.14 在 SWI 指令的编码格式中,后 24 位称为指令的“comment field“。该域保存的24 位数,即为 SWI 指令的
30、中断号。10.4.11.15 下面是一个 SWI 的中断处理程序.SWI_Handler: STMFD sp!, r0-r12,lr ;保存寄存器 LDR r0, lr,#-4 ;计算 SWI 指令地址 BIC r0, r0, #0xff000000 ;提取指令编码的后 24 位 ; ; 提取出的中断号放 r0 寄存器,函数返回 ; LDMFD sp!, r0-r12,pc ;恢复寄存器在这个例子中,使用 LR-4 得到 SWI 指令的地址,再通过“BIC r0, r0, #0xff000000“指令提取 SWI 指令中断号。十一、ARM 汇编语言程序的介绍11.1 一个最简单的程序AREA
31、XXH, CODE, READONLY ;声明代码段CODE32 ;声明为 32 位 ARM 指令ENTRY ;声明程序入口START MOV R0 ,#0MOV R1, #1ADD R1, R1, R0B STARTEND11.2 在 ARM 汇编程序中用“;”号进行注释。11.3 一个完整的 ARM 汇编由两部分组成:声明,实际代码段两部分组成。11.4 声明:在一个程序之前先要进行声明11.4.1 声明代码段:用 AREA 指令定义一个段,说明所定义段的相关属性(说明段的名字,段的属性)11.4.2 声明 ARM 指令:用 CODE32 或 CODE16 来声明程序为 32 位 ARM
32、指令或是 16 位Thumb 指令。11.4.3 声明程序入口:用 ENTRY 指令标识程序的入口点。11.4.4 在程序完成后要用 END 指令声明程序结束。每一个汇编程序段都必须有一条 END指令,指示代码段的结束。11.5 段:在 ARM 汇编语言程序中,以程序段为单位组织代码。段是相对独立的指令或数据序列,具有特定的名称。11.6 段的分类11.6.1 代码段: 代码段的内容为执行代码11.6.2 数据段: 数据段存放代码运行时需要用到的数据。11.6.3 代码段一般具有 READONLY 属性。11.6.4 数据段一般具有 READWRITE 属性。11.6.5 一个汇编程序至少有一
33、个代码段。如果程序较长时,可以分割为多个代码段和数据段。多个段在程序编译连接时最终形成一个可执行的映像文件。11.7 汇编语言的语句格式LABEL OPERATION OPERAND ;COMMENT11.7.1 LABEL。 标号域用来表示指令的地址、变量、过程名、数据的地址和常量。 语句标号必须在一行的开头书写,不能留空格。11.7.2 操作助记符域(OPERATION)。 操作助记符域可以为指令、伪操作、宏指令或伪指令的助记符。 所有的指令都不能在行的开头书写,必须在指令的前面有空格,然后再书写指令。 可以为大写,也可以为小写。但是,不能大小写混写。 指令助记符和后面的操作数或操作寄存器
34、之间必须有空格,不可以在它们之间使用逗号。 伪操作是 ARM 汇编语言程序里的一些特殊助记符,其作用主要是为完成汇编程序做的各种准备工作,在源程序进行汇编时由汇编程序处理,而不是程序运行期间由机器执行。 宏指令是一段在独立的程序代码,可插在源程序中,它通过伪操作来定义。宏在使用之前必须提前定义好,宏之间可互相调用,也可递归调用。 伪指令是 ARM 汇编语言程序里的特殊指令助记符,也不在程序运行期间由机器执行。它们在汇编时将被合适的机器指令代替成 ARM 或 Thumb 指令,从而实现真正的指令操作。11.7.3 操作数域(OPERAND)。操作数域表示操作的对象,操作数可以是常量、变量、标号、
35、寄存器名或表达式,不同对象之间必须用逗号“, ”分开。实例:十二、汇编语言程序中常用的符号12.1 在汇编语言程序设计中,经常使用各种符号表示变量、常量和地址等,以增加程序的可读性。12.2 符号的命名必须遵循以下约定: 由大小写字母、数字以及下划线组成。 区分大小写,同名的大、小写符号会被编译器认为是两个不同的符号。 符号在其作用范围内必须唯一,即在其作用范围内不可有同名的符号。 自定义的符号名不能与系统的保留字相同。 符号名不应与指令或伪指令同名。12.3 程序中的变量 程序中的变量是指其值在程序的运行过程中可以改变的量。 通过定义变量可以简化程序的表达,增强程序的可读性,方便对程序进行修
36、改,便于交流和记忆。 同时编译程序会自动安排变量的存储空间,程序设计工程师可以不必去关心存储空间的安排,因此一个好的程序设计工程师应该恰当地使用变量。 ARM 汇编程序所支持的变量有数值变量、逻辑变量和字符串变量。 使用 GBLA、GBLL 、GBLS 伪操作声明全局变量。 使用 LCLA、LCLL 、LCLS 伪操作声明局部变量。 使用 SETA、SETL 和 SETS 对变量进行初始化。 数值变量的值的大小不应超过一个 32 位数所能表示的范围。全局数值变量使用伪操作 GBLA 定义,局部数值变量使用伪操作 LCLA 定义。数值变量使用SETA 赋值。 逻辑变量。全局逻辑变量使用伪操作 G
37、BLL 定义,局部逻辑变量使用伪操作LCLL 定义。逻辑变量使用 SETL 赋值。 字符串变量。长度不得越出 512 字节,最小长度为 0,全局字符变量使用伪操作 GBLS 定义,局部字符变量使用伪操作 LCLS 定义,使用 SETS 赋值。12.4 程序中的常量 常量,程序的运行过程中不能被改变的量。ARM 汇编程序的常量:数值常量、逻辑常量、字符串常量。 数值常量。32 位整数,无符号数的取值范围为 0 到 232-1,有符号数的取值范围为-231 到 231-1。使用 EQU 定义数值常量 十进制数:在表达式中可以直接表达,例如:1、2 、 233。 十六进数:采用前缀 0x,例如 0x
38、003;或者使用前缀定义一个全局的数字变量,变量名为 Test1Test1 SETA 0xaa ;将该变量赋值为 0xaaGBLL Test2 ;定义一个全局的逻辑变量,变量名为 Test2Test2 SETL TRUE ;将该变量赋值为真GBLS Test3 ;定义一个全局的字符串变量,变量名为Test3Test3 SETS “Testing“ ;将该变量赋值为“Testing”14.3.2 局部变量定义伪操作 LCLA、LCLL 和 LCLSLCLA Test4 ;声明一个局部的数字变量,变量名为 Test4Test3 SETA 0xaa ;将该变量赋值为 0xaaLCLL Test5 ;
39、声明一个局部的逻辑变量,变量名为 Test5Test4 SETL TRUE ;将该变量赋值为真LCLS Test6 ;定义一个局部的字符串变量,变量名为Test6Test6 SETS “Testing“ ;将该变量赋值为“Testing”14.3.3 变量赋值伪操作 SETA、SETL 和 SETS伪指令 SETA、 SETL 和 SETS 用于给一个已经定义的全局变量或局部变量赋值。SETA 伪操作用于给一个数学变量赋值;SETL 伪操作用于给一个逻辑变量赋值;SETS 伪操作用于给一个字符串变量赋值;14.3.4 通用寄存器列表定义伪操作 RLIST对一个通用寄存器列表定义名称。这个名称可
40、在 ARM 指令 LDM/STM 中使用。在 LDM/STM 指令中,列表中的寄存器访问次序根据寄存器的编号由低到高,与列表中的寄存器排列次序无关。格式如下:Name RLIST list-of-registers14.3.5 协处理器寄存器名称定义伪操作 CN(略)14.3.6 协处理器名称定义伪操作 CP(略)14.3.7 VFP 寄存器名称定义伪操作 DN/SN(略)14.3.8 浮点寄存器名称定义伪操作 FN(略)14.4 数据定义伪操作14.4.1 数据定义伪指令一般用于为特定的数据分配存储单元,同时可完成已分配存储单元的初始化。常见的数据定义伪指令有如下几种: DCB 用于分配一片
41、连续的字节存储单元并用指定的数据初始化。 DCW(DCWU )用于分配一片连续的半字存储单元并用指定的数据初始化。 DCD(DCDU )用于分配一片连续的字存储单元并用指定的数据初始化。 DCFD(DCFDU)用于为双精度的浮点数分配一片连续的字存储单元并用指定的数据初始化。 DCFS(DCFSU)用于为单精度的浮点数分配一片连续的字存储单元并用指定的数据初始化。 DCQ(DCQU )用于分配一片以 8 字节为单位的连续的存储单元并用指定的数据初始化。 SPACE 用于分配一片连续的存储单元 MAP 用于定义一个结构化的内存表首地址 FIELD 用于定义一个结构化的内存表的数据域14.4.2
42、DCB 语法格式:标号 DCB 表达式 功能:DCB 伪指令用于分配一片连续的字节存储单元,并用伪指令中指定的表达式初始化。 表达式可以为 0255 的数字或字符串。 DCB 也可用“= ”代替。 使用示例:Str DCB “This is a test !” ;分配一片连续的字节存储单元并初始化。14.4.3 DCW(或 DCWU) 语法格式:标号 DCW(或 DCWU) 表达式 功能:DCW(或 DCWU)伪指令用于分配一片连续的半字存储单元并用伪指令中指定的表达式初始化。 表达式可以为程序标号或数字表达式。 用 DCW 分配的字存储单元是半字对齐的,而用 DCWU 分配的字存储单元并不严
43、格半字对齐。 使用示例:DataTest DCW 1, 2, 3 ;分配一片连续的半字存储单元并初始化。14.4.4 DCD(或 DCDU) 语法格式:标号 DCD (或 DCDU )表达式 功能:DCD(或 DCDU)伪指令用于分配一片连续的字存储单元并用伪指令中指定的表达式初始化。 表达式可以为程序标号或数字表达式。DCD 也可用“32 位的字单元,其值为标号 START1 基于 R9 的偏移量14.4.6 DCI 语法格式:标号 DCI 表达式 功能:在 ARM 代码中,用于分配一段字对齐的字内存单元,并用表达式将其初始化;在 Thumb 代码中,用于分配一段半字对齐的半字内存单元,并用
44、表达式将其初始化。DCI 伪操作与 DCD 非常相似,不同之处在于,DCI 分配的内存中数据被标识为指令,可用于通过宏指令来定义处理器指令系统不支持的指令。 使用示例:MACRO ;宏指令NEWCMD $Rd, $RmDCI 0xe16f0f10: OR( $Rd:SHL:12):OR:$Rm ;这里存放的是指令MEND14.4.7 DCFD(或 DCFDU) 语法格式:标号 DCFD (或 DCFDU )表达式 功能:DCFD (或 DCFDU)伪指令用于为双精度的浮点数分配一片连续的字存储单元并用伪指令中指定的表达式初始化。 每个双精度的浮点数占据两个字单元。用 DCFD 分配的字存储单元
45、是字对齐的,而用 DCFDU 分配的字存储单元并不严格字对齐。 使用示例:FDataTest DCFD 2E115 , -5E7 ;分配一片连续的字存储单元并初始化为指定的双精度数。14.4.8 DCFS(或 DCFSU) 语法格式: 标号 DCFS (或 DCFSU )表达式 DCFS(或 DCFSU)伪指令用于为单精度的浮点数分配一片连续的字存储单元并用伪指令中指定的表达式初始化。每个单精度的浮点数占据一个字单元。用 DCFS分配的字存储单元是字对齐的,而用 DCFSU 分配的字存储单元并不严格字对齐。 使用示例:FDataTest DCFS 2E5 , -5E-7 ;分配一片连续的字存储
46、单元并初始化为指定的单精度数。14.4.9 DCQ(或 DCQU) 语法格式: 标号 DCQ (或 DCQU )表达式 DCQ(或 DCQU)伪指令用于分配一片以 8 个字节为单位的连续存储区域并用伪指令中指定的表达式初始化。 用 DCQ 分配的存储单元是字对齐的,而用 DCQU 分配的存储单元并不严格字对齐。 使用示例:DataTest DCQ 100 ;分配一片连续的存储单元并初始化为指定的值。14.4.10SPACE 语法格式: 标号 SPACE 表达式 SPACE 伪指令用于分配一片连续的存储区域并初始化为 0。其中,表达式为要分配的字节数。SPACE 也可用“ ”代替。 使用示例:D
47、ataSpace SPACE 100 ;分配连续 100 字节的存储单元并初始化为 0 。14.4.11MAP 语法格式: MAP 表达式 ,基址寄存器 MAP 伪指令用于定义一个结构化的内存表的首地址。MAP 也可用“”代替。 表达式可以为程序中的标号或数学表达式,基址寄存器为可选项,当基址寄存器选项不存在时,表达式的值即为内存表的首地址,当该选项存在时,内存表的首地址为表达式的值与基址寄存器的和。 MAP 伪指令通常与 FIELD 伪指令配合使用来定义结构化的内存表。 使用示例:MAP 0x100 , R0 ;定义结构化内存表首地址的值为 0x100 R0 。14.4.12FILED 语法
48、格式:标号 FIELD 表达式 FIELD 伪指令用于定义一个结构化内存表中的数据域。FILED 也可用“# ”代替。 表达式的值为当前数据域在内存表中所占的字节数。 FIELD 伪指令常与 MAP 伪指令配合使用来定义结构化的内存表。MAP 伪指令定义内存表的首地址,FIELD 伪指令定义内存表中的各个数据域,并可以为每个数据域指定一个标号供其他的指令引用。 注意 MAP 和 FIELD 伪指令仅用于定义数据结构,并不实际分配存储单元。 使用示例:14.4.13LTORG 语法格式:LTORG 功能:用于声明一个数据缓冲池(也称为文字池)的开始,当程序中使用 LDR 之类的指令时,数据缓冲区的使用可能越界。为防止越界发生,可使用 LTORG 伪操作定义数据缓冲池。ARM 汇编编译器一般把数据缓冲池放在代码段的最后面,即下一个代码段开始之前或者 END 伪操作之前。LTORG 伪操作通常放在无条件跳转指令之后,或者子程序返回指令之后,这样处理器就不会错误地将数据缓冲池中的数据当作指令来执行。例如:十五、汇编控制伪操作汇编控制伪操作用于控制汇编程序的执行流程,常用的汇编控制伪操作包括IF、ELSE、ENDIF;WHILE、WEND ;MACRO 、MEND 、MEXIT。15.1 IF、ELSE、ENDIF 功能:根据条件的成立与否,决定执