Arm微处理器编程
Made by 哲 ^ ^
1、RISC处理器体系结构概述
计算机语言对比
机器语言:依赖于机器的低级语言,书写格式为二进制代码。
优点:执行速度快,效率高。
缺点:表达的意义不直观,编写、阅读、调试较困难。
汇编语言:是一种符号语言,与机器语言一一对应;使用助记
符表示相应的操作,并遵循一定的语法规则。与机
器语言有类似的优、缺点,但比机器语言更易于为
人们所理解。
高级语言:面向人的语言,有多种类型。
优点:便于阅读,易学易用,不涉及硬件,具有通用性。
缺点:目标代码冗长,占用内存多,从而执行时间长,效
率不高,不能对某些硬件进行操作。
汇编语言的特点:
·面向机器的低级语言,通常是为特定的计算机或计算机系列
专门设计的。(ISA体系结构,面向特定的处理器)
· 保持了机器语言的优点,具有直接和简洁的特点。
· 可有效地访问、控制计算机的各种硬件设备,如磁盘、存储
器、CPU、I/O端口等。
· 目标代码简短,占用内存少,执行速度快,是高效的程序设
计语言。
· 经常与高级语言配合使用(混合编程),应用十分广泛。
汇编语言的应用:
·70%以上的系统软件是用汇编语言编写的。
· 某些快速处理、位处理、访问硬件设备等高效程序是用
汇编语言编写的。
· 某些高级绘图程序、视频游戏程序、图像解压缩程序是用汇编语言编写的。
RISC处理器体系结构概述:
ISA体系结构分类
根据指令使用数据的方式,指令系统分为以下几类
**堆栈型(Stack):**操作数在栈顶,运算操作不用指定操作数
累加器型(Accumulator):一个操作数总在累加器中,结果也写回累加器
寄存器型(Register),每个操作数都由指令指定
**Register-Register型,**又称为Load-Store型,所有运算操作的操作数都在寄存器中
Register-Memory型
Memory-Memory型
上述三种指令系统类型也可以分别称为0地址指令,单地址指令,以及多地址指令
CISC复杂指令集计算机
cisc的特点:
指令格式不固定,指令可长可短,操作数可多可少;
寻址方式复杂多样,操作数可来自寄存器,也可来自存储器;
采用微程序控制,执行每条指令均需完成一个微指令序列;
CPI > 5,指令越复杂,CPI越大。
cisc的缺点:
指令集虽大,但指令使用频度不均衡;20%/80%定律:20%的指令的使用时间占80%的运行时间;常用指令数仅占指令集总数的10-20%。
微程序控制器制约了速度提高,因为存放微码的存储器速度比CPU慢5-10倍;CPI很大;
CISC不利于先进指令级并行(ILP)技术的采用;
编译器代码优化困难。
RISC体系结构 <精简指令集>
RISC基本设计思想:
减小CPI:
CPUtime=Instr_Count * CPI * Clock_cycle
精简指令集:保留最基本的,去掉复杂的,使用频度不高的指令
采用Load/Store结构,有助于大大减少指令格式,统一了存储器访问方式
采用硬接线控制代替微程序控制
RISC结构的特点:
寻址方式少,指令格式少且规整,指令长度统一(32bit),便于提高流水线效率。(见MIPS指令格式)
Load/store指令结构
大寄存器文件(32个32位寄存器)
CPI接近于1,大多数指令单周期完成
硬接线控制器
有助于编译优化代码
CISC vs. RISC
CISC 复杂指令集计算机
指令多,功能复杂,线路复杂
指令长度不一,编程简单,控制复杂;
寻址方式多,复杂;
每条指令的执行周期数CPI在1~20;
RISC 精简指令集计算机
定长指令,条数少,多级流水线;
指令简化令机器结构简单,译码简单统一、优化;
寻址方式少,简单;
特定指令访问内存,如:Load,Store;
每条指令的执行周期数CPI在1~2;
流水线技术
什么是流水线(pipeline)
流水线是实现多条指令重叠执行的技术,是加快CPU执行速度的关键技术。
术语:
流水级(pipe stage):流水线由多个流水级组成,通常一条指令由n级流水级完成。每个流水级完成指令的部分任务。
吞吐量(throughput):单位时间内流出流水线的指令数。
机器周期
不同流水线完成指令功能不等,所需时间有长有短,因此设计流水线的关键是合理划分指令功能,使每一流水级完成指令功能的时间大致相等。
机器周期由最长流水级的时间决定,通常等于时钟周期。
5级流水
1、取指令 IF
2、译码/读寄存器 ID
3、执行/有效地址计算 EX
4、存储器访问/转移完成 MEM
5、写回 WB
2、ARM体系结构概述
ARM微处理器简介
成立于1990年11月
前身为 Acorn计算机公司
ARM (Advance RISC Machine)
主要设计ARM系列RISC处理器内核
授权ARM内核给生产和销售半导体的合作伙伴
ARM 公司不生产芯片
IP(Intelligence Property)
另外也提供基于ARM架构的开发设计技术
软件工具,评估板,调试工具,应用软件
总线架构,外围设备单元,等等
ARM微处理器的应用领域及特点
ARM微处理器的应用领域
工业控制领域 :高端微控制器
无线通讯领域 :无线通讯设备
网络应用 :宽带技术、语音及视频处理
消费类电子产品 :数字音频播放器、数字机顶盒和游戏机
成像和安全产品 :数码相机、打印机及32位SIM智能卡
ARM微处理器的特点
采用RISC架构的ARM微处理器具有如下特点:
体积小、低功耗、低成本、高性能;
支持Thumb(16位)/ARM(32位)双指令集,能很好的兼容8位/16位器件;
大量使用寄存器,指令执行速度更快;
大多数数据操作都在寄存器中完成;
寻址方式灵活简单,执行效率高;
指令长度固定
ARM体系的特别技术
在同一条数据处理指令中包含算术逻辑处理单元处理和移位处理。
使用地址自动增加(减少)来优化程序中循环处理。
load/store指令可以批量传输数据,从而提高数据传输的效率。
所有指令都可以条件执行。
ARM7微处理器系列(P.7)
ARM7系列微处理器为低功耗的32位RISC处理器(三级流水:IF,ID,EX),最适合用于对价位和功耗要求较高的消费类应用。
ARM7TDMI 是基于 ARM7 内核
3 级流水线—0.9MIPS/MHz
冯.诺依曼架构:只有数据存储器接口,同时用来取指令和数据访问。
CPI(Clock-Cycle Per Instruction) 约为1.9
ARM7没有MMU,ARM720T是MMU的
T - Thumb 架构扩展, 提供两个独立的指令集:
ARM 指令,均为 32位
Thumb指令,均为 16位
两种运行状态,用来选择哪个指令集被执行
D - 内核具有Debug扩展结构
M - 增强乘法器 (32x32) 支持64位结果.
I - Embedded ICE-RT逻辑—提供片上断点和调试点支持
ARM MMU工作原理
MMU: Memory Management Unit
CPU管理虚拟存储器、物理存储器,也负责虚拟地址映射为物理地址。
虚拟地址空间划分成称为页(page)的单位
而相应的物理地址空间也被进行划分,单位是页框(frame)
页和页框的大小必须相同。
1.3.2 ARM9微处理器系列(P.8)
ARM9系列微处理器在高性能和低功耗特性方面提供最佳的性能。具有以下特点:
5级整数流水线,指令执行效率更高。
提供1.1MIPS/MHz的哈佛结构:独立的指令和数据存储器接口,可同时取指和读写数据。
实现了一个周期完成loads指令和stores指令
引入了独立的存储器和写回流水线,分别用来访问存储器和将结果写回寄存器。
支持32位ARM指令集和16位Thumb指令集。
支持32位的高速AMBA总线接口。
全性能的MMU,支持Windows CE、Linux、Palm OS等多种主流嵌入式操作系统。
MPU支持实时操作系统。
支持数据Cache和指令Cache,具有更高的指令和数据处理能力。
增强性乘法器设计
ARM9系列微处理器主要应用于无线设备、仪器仪表、安全系统、机顶盒、高端打印机、数字照相机和数字摄像机等。
ARM9系列微处理器包含ARM920T、ARM922T和ARM940T三种类型,以适用于不同的应用场合。
ARM9主要应用
无线网络设备:手机上网、电子邮件及其他定位服务等功能;
PDA功能:含有用户操作系统(Windows CE、Symbian OS、Linux等)及其他功能;
高性能功能:音频播放器、视频电话、手机游戏等。
在2.5G和3G的应用中ARM9已经全面替代了ARM7。
ARM9典型处理器:S3C2440
互锁(interlocks)技术
当指令需要的数据因为以前的指令没有执行完而没有准备好就会产生管道自锁互锁。
当管道互锁发生时,硬件会停止这个指令的执行,直到数据准备好为止。
编译器以及汇编程序员可以通过重新设计代码的顺序或者其他方法来减少管道互锁的数量。
ARM10E微处理器系列(P.9)
ARM10E系列微处理器具有高性能、低功耗的特点,由于采用了新的体系结构,与同等的ARM9器件相比较,在同样的时钟频率下,性能提高了近50%,同时,ARM10E系列微处理器采用了两种先进的节能方式,使其功耗极低。
ARM10E系列微处理器的主要特点如下:
支持DSP指令集,适合于需要高速数字信号处理的场合。
6级整数流水线,指令执行效率更高。
支持32位ARM指令集和16位Thumb指令集。
支持32位的高速AMBA总线接口。
支持VFP10浮点处理协处理器。
全性能的MMU,支持Windows CE、Linux、Palm OS等多种主流嵌入式操作系统。
支持数据Cache和指令Cache,具有更高的指令和数据处理能力
主频最高可达400MIPS。
内嵌并行读/写操作部件,支持64位的load/store体系。
ARM10E系列微处理器主要应用于下一代无线设备、数字消费品、成像设备、工业控制、通信和信息系统等领域。
ARM10E系列微处理器包含ARM1020E、ARM1022E和ARM1026EJ-S三种类型,以适用于不同的应用场合。
ARM微处理器结构
1.4.1 RISC体系结构
一般认为: RISC体系结构应具有如下特点:
采用固定长度的指令格式,指令归整、简单、基本寻址方式有2~3种。
使用单周期指令,便于流水线操作执行。
大量使用寄存器,数据处理指令只对寄存器进行操作,只有加载/ 存储指令可以访问存储器,以提高指令的执行效率。
除此以外,ARM体系结构还采用了一些特别的技术,在保证高性能的前提下尽量缩小芯片的面积,并降低功耗:
所有的指令都可根据前面的执行结果决定是否被执行,从而提高指令的执行效率。(条件执行)
可用加载/存储指令批量传输数据,以提高数据的传输效率。
可在一条数据处理指令中同时完成逻辑处理和移位处理。
在循环处理中使用地址的自动增减来提高运行效率。
ARM协处理器
多达16个可定义协处理器,用唯一的ID来标示
扩充ARM指令集
通常用作ARM “internal functions” (例如:cp15通常 用作 ARM cache 控制器)
通常系统设计的时候最好用内存映射外设
容易实现
1.4.2 数据和指令类型
ARM 采用的是32位架构.
ARM 约定:
Byte : 8 bits (1 byte)
Halfword : 16 bits (2 bytes)
Word : 32 bits (4 bytes)
大部分ARM core 提供:
ARM 指令集(32-bit)
Thumb 指令集(T变种)(16-bit )
1.4.3 ARM体系结构的异常中断
ARM 有7个基本工作模式:
User:非特权模式,大部分任务执行在这种模式
正常程序执行的模式
FIQ:当一个高优先级(fast)中断产生时将会进入这种模式
高速数据传输和通道处理
IRQ:当一个低优先级(normal)中断产生时将会进入这种模式
通常的中断处理
Supervisor:当复位或软中断指令执行时将会进入这种模式
供操作系统使用的一种保护模式
Abort: 当存取异常时将会进入这种模式
虚拟存储及存储保护(指令预取和存取操作)
Undef: 当执行未定义指令时会进入这种模式
软件仿真硬件协处理器
System: 使用和User模式相同寄存器集的特权模式
特权级的操作系统任务
1.4.4 ARM微处理器的寄存器结构(P.11)
ARM处理器共有37个寄存器,被分为若干个组(bank),这些寄存器包括:
31个通用寄存器,包括程序计数器(PC指针),均为32位的寄存器。
6个状态寄存器,用以标识CPU的工作状态及程序的运行状态,均为32位,目前只使用了其中的一部分。
同时,ARM处理器又有7种不同的处理器模式,在每一种处理器模式下均有一组相应的寄存器与之对应。即在任意一种处理器模式下,可访问的寄存器包括15个通用寄存器(R0~R14)、一至二个状态寄存器和程序计数器。在所有的寄存器中,有些是在7种处理器模式下共用的同一个物理寄存器,而有些寄存器则是在不同的处理器模式下有不同的物理寄存器。
异常处理
当异常产生时, ARM core:
拷贝 CPSR 到 SPSR_
设置适当的 CPSR 位:
改变处理器状态进入 ARM 态
改变处理器模式进入相应的异常模式
设置中断禁止位禁止相应中断 (如果需要)
保存返回地址到 LR_
设置 PC 为相应的异常向量
返回时, 异常处理需要:
从 SPSR_恢复CPSR
从LR_恢复PC
Note:这些操作只能在 ARM 态执行.
1.4.3 ARM微处理器的指令结构
ARM微处理器的在较新的体系结构中支持两种指令集:
ARM指令集
Thumb指令集
其中,ARM指令为32位的长度,Thumb指令为16位长度。Thumb指令集为ARM指令集的功能子集,但与等价的ARM代码相比较,可节省30%~40%以上的存储空间,同时具备32位代码的所有优点。
ARM指令集
所有ARM指令均为32-bits长
大部分为单周期指令
所有指令都可以条件执行
采用 Load/Store 架构
Thumb指令集
Thumb 是一个 16-bits 指令集
优化代码密度 (~65% of ARM )
提高窄内存操作性能
是ARM指令集的一个功能子集
ARM / Thumb 转换使用 BX 指令
对于由编译器产生的绝大多数指令:
条件执行不可用
源和目的寄存器相同
只有低端寄存器可用
常量大小受限制
内嵌的桶形移位不可用
3、ARM微处理器的编程模型
ARM微处理器的工作状态
从编程的角度看,ARM微处理器的工作状态一般有两种,并可在两种状态之间切换:
第一种为ARM状态,此时处理器执行32位的字对齐的ARM指令;
第二种为Thumb状态,此时处理器执行16位的半字对齐的Thumb指令。
当ARM微处理器执行32位的ARM指令集时,工作在ARM状态;
当ARM微处理器执行16位的Thumb指令集时,工作在Thumb状态。
在程序的执行过程中,微处理器可以随时在两种工作状态之间切换,并且,处理器工作状态的转变并不影响处理器的工作模式和相应寄存器中的内容。
大端格式:在这种格式中,字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中
小端格式:
与大端存储格式相反,在小端存储格式中,低地址中存放的是字数据的低字节,高地址存放的是字数据的高字节。
指令长度及数据类型
ARM微处理器的指令长度可以是32位(在ARM状态下),也可以为16位(在Thumb状态下)。
ARM微处理器中支持三种数据类型:
字节(8位)
半字(16位)
字(32位)
其中,字需要4字节对齐(地址的低两位为0,这样地址一定是四的倍数)、半字需要2字节对齐(地址的最低位为0)。
处理器模式
ARM微处理器支持7种运行模式,分别为:
用户模式(usr):ARM处理器正常的程序执行状态
快速中断模式(fiq):用于高速数据传输或通道处理
外部中断模式(irq):用于通用的中断处理
管理模式(svc):操作系统使用的保护模式(复位或软中断)
数据访问终止模式(abt):当数据或指令预取终止时进入该模式,可用于虚拟存储及存储保护。
系统模式(sys):运行具有特权的操作系统任务。
未定义指令中止模式(und):当未定义的指令执行时进入该模式,可用于支持硬件协处理器的软件仿真。
ARM微处理器的运行模式可以通过软件改变,也可以通过外部中断或异常处理改变。
大多数的应用程序运行在用户模式下,当处理器运行在用户模式下时,某些被保护的系统资源是不能被访问的。
除用户模式以外,其余的所有6种模式称之为非用户模式,或特权模式(Privileged Modes);其中除去用户模式和系统模式以外的5种又称为异常模式(Exception Modes),常用于处理中断或异常,以及需要访问受保护的系统资源等情况。
寄存器组织
ARM微处理器共有37个32位寄存器,其中31个为通用寄存器,6个为状态寄存器。但是这些寄存器不能被同时访问,具体哪些寄存器是可编程访问的,取决微处理器的工作状态及具体的运行模式。
但在任何时候,通用寄存器R0~R14、程序计数器PC、一个或两个状态寄存器都是可访问的。
ARM状态下的寄存器组织
通用寄存器:
通用寄存器包括R0~R15,可以分为三类:
未分组寄存器R0~R7
分组寄存器R8~R14
程序计数器PC(R15)
未分组寄存器R0~R7:
在所有的运行模式下,未分组寄存器都指向同一个物理寄存器,他们未被系统用作特殊的用途,因此,在中断或异常处理进行运行模式转换时,由于不同的处理器运行模式均使用相同的物理寄存器,可能会造成寄存器中数据的破坏,这一点在进行程序设计时应引起注意。
分组寄存器R8~R14:
对于分组寄存器,每一次所访问的物理寄存器与处理器当前的运行模式有关。
对于R8~R12来说,每个寄存器对应两个不同的物理寄存器,当使用fiq模式时,访问寄存器R8_fiq~R12_fiq;当使用除fiq模式以外的其他模式时,访问寄存器R8_usr~R12_usr。
ARM 有37个32-Bits长的寄存器.
1 个用作PC
1个用作CPSR
5个用作SPSR
30 个通用寄存器
当前处理器的模式决定着哪组寄存器可操作. 任何模式都可以存取:
相应的r0-r12子集
相应的 r13 (sp) and r14 (lr)
相应的 r15 (pc)
相应的CPSR
特权模式 (除system模式) 还可以存取;
相应的 SPSR
对于R13、R14来说,每个寄存器对应6个不同的物理寄存器,其中的一个是用户模式与系统模式共用,另外5个物理寄存器对应于其他5种不同的运行模式。
采用以下的记号来区分不同的物理寄存器:
R13_
R14_
其中,mode为以下几种模式之一:usr、fiq、irq、svc、abt、und。
寄存器R13在ARM指令中常用作堆栈指针,但这只是一种习惯用法,用户也可使用其他的寄存器作为堆栈指针。
而在Thumb指令集中,某些指令强制性的要求使用R13作为堆栈指针。
由于处理器的每种运行模式均有自己独立的物理寄存器R13,在用户应用程序的初始化部分,一般都要初始化每种模式下的R13,使其指向该运行模式的栈空间,这样,当程序的运行进入异常模式时,可以将需要保护的寄存器放入R13所指向的堆栈,而当程序从异常模式返回时,则从对应的堆栈中恢复,采用这种方式可以保证异常发生后程序的正常执行。
R14也称作子程序连接寄存器(Subroutine Link Register)或连接寄存器LR。当执行BL子程序调用指令时,R14中得到R15(程序计数器PC)的备份。其他情况下,R14用作通用寄存器。
与之类似,当发生中断或异常时,对应的分组寄存器R14_svc、R14_irq、R14_fiq、R14_abt和R14_und用来保存R15的返回值。
寄存器R14常用在如下的情况:
在每一种运行模式下,都可用R14保存子程序的返回地址。当用BL或BLX指令调用子程序时,将PC的当前值拷贝给R14,执行完子程序后,又将R14的值拷贝回PC,即可完成子程序的调用返回。以上的描述可用指令完成:
1、执行以下任意一条指令可以返回:
MOV PC,LR ;PC LR
或 BX LR
2、在子程序入口处使用以下指令将R14存入堆栈:
STMFD SP!,{,LR}
对应的,使用以下指令可以完成子程序返回:
LDMFD SP!,{,PC}
R14也可作为通用寄存器。
程序计数器PC(R15)
寄存器R15用作程序计数器(PC)。在ARM状态下,位[1:0]为0,位[31:2]用于保存PC;在Thumb状态下,位[0]为0,位[31:1]用于保存PC;
R15虽然也可用作通用寄存器,但一般不这么使用,因为对R15的使用有一些特殊的限制,当违反了这些限制时,程序的执行结果是未知的。
由于ARM体系结构采用了多级流水线技术,对于ARM指令集而言,PC总是指向当前指令的下两条指令的地址,即PC的值为当前指令的地址值加8个字节。(?P.14)
当处理器执行在ARM状态:
所有指令 32 bits 宽
所有指令必须 word 对齐
pc值由bits [31:2]决定, bits [1:0] 未定义 (所以指令不能halfword / byte对齐).
当处理器执行在Thumb状态:
所有指令 16 bits 宽
所有指令必须 halfword 对齐
pc值由bits [31:1]决定, bits [0] 未定义 (所以指令不能 byte对齐).
当前程序状态寄存器:
寄存器的名字为CPSR(Current Program Status Register,当前程序状态寄存器),CPSR可在任何运行模式下被访问,它包括条件标志位、中断禁止位、当前处理器模式标志位,以及其他一些相关的控制和状态位。
每一种运行模式下又都有一个专用的物理状态寄存器,称为SPSR(Saved Program Status Register,备份的程序状态寄存器),当异常发生时,SPSR用于保存CPSR的当前值,从异常退出时则可由SPSR来恢复CPSR。
由于用户模式和系统模式不属于异常模式,他们没有SPSR,当在这两种模式下访问SPSR,结果是未知的。
(详细介绍见后)
Thumb状态下的寄存器组织
Thumb状态下的寄存器集是ARM状态下寄存器集的一个子集,程序可以直接访问8个通用寄存器(R0~R7)、程序计数器(PC)、堆栈指针(SP)、连接寄存器(LR)和CPSR。
同时,在每一种特权模式下都有一组SP、LR和SPSR。下图表明Thumb状态下的寄存器组织。
访问Thumb状态下的高位寄存器(Hi-registers):
在Thumb状态下,高位寄存器R8~R15并不是标准寄存器集的一部分,但可使用汇编语言程序有限制的访问这些寄存器,将其用作快速的暂存器。
使用带特殊变量的MOV指令,数据可以在低位寄存器和高位寄存器之间进行传送;
高位寄存器的值可以使用CMP和ADD指令进行比较或加上低位寄存器中的值。
程序状态寄存器CPSR
条件位:
N = 1-结果为负,0-结果为正或0
Z = 1-结果为0,0-结果不为0
C =1-进位,0-借位
V =1-结果溢出,0结果没溢出
Q 位:
仅ARM 5TE/J架构支持
指示增强型DSP指令是否溢出
J 位
仅ARM 5TE/J架构支持
J = 1: 处理器处于Jazelle状态
中断禁止位:
I = 1: 禁止 IRQ.
F = 1: 禁止 FIQ.
T Bit
仅ARM xT架构支持
T = 0: 处理器处于 ARM 状态
T = 1: 处理器处于 Thumb 状态
Mode位(处理器模式位):
0b10000 User
0b10001 FIQ
0b10010 IRQ
0b10011 Supervisor
0b10111 Abort
0b11011 Undefined
0b11111 System
对异常的响应
当一个异常出现以后,ARM微处理器会执行以下几步操作:
1、将下一条指令的地址存入相应连接寄存器LR,以便程序在处理异常返回时能从正确的位置重新开始执行。若异常是从ARM状态进入,LR寄存器中保存的是下一条指令的地址(当前PC+4或PC+8,与异常的类型有关);若异常是从Thumb状态进入,则在LR寄存器中保存当前PC的偏移量,这样,异常处理程序就不需要确定异常是从何种状态进入的。例如:在软件中断异常SWI,指令 MOV PC,R14_svc总是返回到下一条指令,不管SWI是在ARM状态执行,还是在Thumb状态执行。
2、将CPSR复制到相应的SPSR中。
3、根据异常类型,强制设置CPSR的运行模式位。
4、强制PC从相关的异常向量地址取下一条指令执行,从而跳转到相应的异常处理程序处。
还可以设置中断禁止位,以禁止中断发生。
如果异常发生时,处理器处于Thumb状态,则当异常向量地址加载入PC时,处理器自动切换到ARM状态。
异常优先级(Exception Priorities)
当多个异常同时发生时,系统根据固定的优先级决定异常的处理次序。异常优先级由高到低的排列次序如下表所示。
优先级 | 异 常 |
---|---|
1(最高) | 复位 |
2 | 数据中止 |
3 | FIQ |
4 | IRQ |
5 | 预取指令中止 |
6(最低) | 未定义指令、SWI |
异常向量(Exception Vectors)
下表显示异常向量地址
地 址 | 异 常 | 进入模式 |
---|---|---|
0x0000,0000 | 复位 | 管理模式 |
0x0000,0004 | 未定义 | 指令未定义模式 |
0x0000,0008 | 软件中断 | 管理模式 |
0x0000,000C | 中止(预取指令) | 中止模式 |
0x0000,0010 | 中止(数据) | 中止模式 |
0x0000,0014 | 保留 | 保留 |
0x0000,0018 | IRQ | IRQ |
0x0000,001C | FIQ | FIQ |
异常进入/退出小节
下表总结了进入异常处理时保存在相应R14中的PC值,及在退出异常处理时推荐使用的指令。
返回指令 | 以前的状态 | 备注 | ||
---|---|---|---|---|
ARM R14_x | Thumb R14_x | |||
BL | MOV PC**,**R14 | PC+4 | PC+2 | 1 |
SWI | MOVS PC**,**R14_svc | PC+4 | PC+2 | 1 |
UDEF | MOVS PC**,**R14_und | PC+4 | PC+2 | 1 |
FIQ | SUBS PC**,R14_fiq,#**4 | PC+4 | PC+4 | 2 |
IRQ | SUBS PC**,R14_irq,#**4 | PC+4 | PC+4 | 2 |
PABT | SUBS PC**,R14_abt,#**4 | PC+4 | PC+4 | 1 |
DABT | SUBS PC**,R14_abt,#**8 | PC+8 | PC+8 | 3 |
RESET | NA | - | - | 4 |
应用程序中的异常处理
当系统运行时,异常可能会随时发生,为保证在ARM处理器发生异常时不至于处于未知状态,在应用程序的设计中,首先要进行异常处理,采用的方式是在异常向量表中的特定位置放置一条跳转指令,跳转到异常处理程序。当ARM处理器发生异常时,程序计数器PC会被强制设置为对应的异常向量,从而跳转到异常处理程序,当异常处理完成以后,返回到主程序继续执行。
4、ARM微处理器的指令系统 - 寻址方式
ARM微处理器的指令的分类与格式
ARM微处理器的指令集是加载/存储型的,也即指令集仅能处理寄存器中的数据,而且处理结果都要放回寄存器中,而对系统存储器的访问则需要通过专门的加载/存储指令来完成。
ARM微处理器的指令集可以分为:
跳转指令
数据处理指令
加载/存储指令
程序状态寄存器(PSR)处理指令
协处理器指令
异常产生指令
六大类,具体的指令及功能如下表所示(表中指令为基本ARM指令,不包括派生的ARM指令)。
ARM指令及功能描述
助记符 | 指令功能描述 |
---|---|
ADC | 带进位加法指令 |
ADD | 加法指令 |
AND | 逻辑与指 |
B | 跳转指令 |
BIC | 位清零指令 |
BL | 带返回的跳转指 |
BLX | 带返回和状态切换的跳转指令 |
BX | 带状态切换的跳转指令 |
CDP | 协处理器数据操作指令 |
助记符 | 指令功能描述 |
---|---|
CMN | 比较反值指令 |
CMP | 比较指令 |
EOR | 异或指令 |
LDC | 存储器到协处理器的数据传输指令 |
LDM | 加载多个寄存器指令 |
LDR | 存储器到寄存器的数据传输指令 |
MCR | 从ARM寄存器到协处理器寄存器的数据传输指令 |
MOV | 数据传送指令 |
助记符 | 指令功能描述 |
---|---|
MRC | 从协处理器寄存器到ARM寄存器的数据传输指令 |
MRS | 传送CPSR或SPSR的内容到通用寄存器指令 |
MSR | 传送通用寄存器到CPSR或SPSR的指 |
MUL | 32位乘法指 |
MLA | 32位乘加指令 |
MVN | 数据取反传送指令 |
ORR | 逻辑或指令 |
RSB | 逆向减法指令 |
RSC | 带借位的逆向减法指令 |
说明
Cond
指令执行的条件编码
Opcode
指令操作符编码
S
决定指令的操作是否影响CPSR的值
Rd
操作目标寄存器编码
Rn
包含第一操作数的寄存器编码
Shifter_operand
表示第二操作数
指令的条件域
当处理器工作在ARM状态时,几乎所有的指令均根据CPSR中条件码的状态和指令的条件域有条件的执行。当指令的执行条件满足时,指令被执行,否则指令被忽略。
每一条ARM指令包含4位的条件码,位于指令的最高4位[31:28]。条件码共有16种,每种条件码可用两个字符表示,这两个字符可以添加在指令助记符的后面和指令同时使用。
例如,跳转指令B可以加上后缀EQ变为BEQ表示“相等则跳转”,即当CPSR中的Z标志置位时发生跳转。
在16种条件标志码中,只有15种可以使用,如表3-2所示,第16种(1111)为系统保留,暂时不能使用。
条件码 | 助记符后缀 | 标 志 | 含 义 |
---|---|---|---|
0000 | EQ | Z置位 | 相等 |
0001 | NE | Z清零 | 不相等 |
0010 | CS | C置位 | 无符号数大于或等于 |
0011 | CC | C清零 | 无符号数小于 |
0100 | MI | N置位 | 负数 |
0101 | PL | N清零 | 正数或零 |
0110 | VS | V置位 | 溢出 |
0111 | VC | V清零 | 未溢出 |
条件码 | 助记符后缀 | 标 志 | 含 义 |
---|---|---|---|
1000 | HI | C置位Z清零 | 无符号数大于 |
1001 | LS | C清零Z置位 | 无符号数小于或等于 |
1010 | GE | N等于V | 带符号数大于或等于 |
1011 | LT | N不等于V | 带符号数小于 |
1100 | GT | Z清零且(N等于V) | 带符号数大于 |
1101 | LE | Z置位或(N不等于V) | 带符号数小于或等于 |
1110 | AL | 忽略 | 无条件执行 |
1111 | NV | 该指令从不执行 |
ARM指令可以通过添加适当的条件码后缀来达到条件执行的目的。
这样可以提高代码密度,减少分支跳转指令数目,提高性能。
CMP r3,#0 BEQ skip ADD r0,r1,r2skip
默认情况下,数据处理指令不影响条件码标志位,但可以选择通过添加“S”来影响标志位。 CMP不需要增加 “S”就可改变相应的标志位。
loop … SUBS r1,r1,#1 BNE loop
ARM指令的寻址方式
所谓寻址方式就是处理器根据指令中给出的地址信息来寻找物理地址的方式。目前ARM指令系统支持如下几种常见的寻址方式。
立即寻址
立即寻址也叫立即数寻址,这是一种特殊的寻址方式,操作数本身就在指令中给出,只要取出指令也就取到了操作数。这个操作数被称为立即数,对应的寻址方式也就叫做立即寻址。例如以下指令:
ADD R0,R0,#1 ;R0←R0+1
ADD R0,R0,#0x3f ;R0←R0+0x3f
在以上两条指令中,第二个源操作数即为立即数,要求以“#”为前缀,对于以十六进制表示的立即数,还要求在“#”后加上“0x”或“&” ,另外%表示二进制数
立即数 (1)
没有任何一条ARM 指令可包括一个32 bit的立即数
所有的ARM指令都是32 bits固定长度
数据处理指令格式中,第二个操作数有12位
4 bit 移位值 (0-15)乘于2,得到一个范围在0-30,步长为 2的移位值。
记住一条准则: “最后8位一定要移动偶数位”.
寄存器寻址
寄存器寻址就是利用寄存器中的数值作为操作数,这种寻址方式是各类微处理器经常采用的一种方式,也是一种执行效率较高的寻址方式。如下指令:
ADD R0,R1,R2 ;R0←R1+R2
该指令的执行效果是将寄存器R1和R2的内容相加,其结果存放在寄存器R0中。
寄存器间接寻址
寄存器间接寻址就是以寄存器中的值作为操作数的地址,而操作数本身存放在存储器中。例如以下指令:
LDR R0,[R1] ;R0←[R1]
STR R0,[R1] ;[R1]←R0
第一条指令将以R1的值为地址的存储器中的数据传送到R0中。
第二条指令将R0的值传送到以R1的值为地址的存储器中。
基址变址寻址
基址变址寻址就是将寄存器(该寄存器一般称作基址寄存器)的内容与指令中给出的地址偏移量相加,从而得到一个操作数的有效地址。变址寻址方式常用于访问某基地址附近的地址单元。
地址偏移量通常有以下三种表示方式:
常量
寄存器
比例(scaled)
偏移寻址(offset addressing)
LDR R0, [R1]
LDR R0, [R1, #4]
LDR R0, [R1, R2]
LDR R0, [R1, R2, LSL #2]
事先更新寻址(pre-index addressing)
LDR R0, [R1, #4]!
LDR R0, [R1, R2]!
LDR R0, [R1, R2, LSL #2]!
事后更新寻址(post-index addressing)
LDR R0, [R1], #4
LDR R0, [R1], R2
LDR R0, [R1], R2, LSL #2
多寄存器寻址
采用多寄存器寻址方式,一条指令可以完成多个寄存器值的传送。这种寻址方式可以用一条指令完成传送最多16个通用寄存器的值。以下指令:
LDMIA R13,{R1,R2,R3,R4} 或写成:LDMIA R13,{R1-R4}
;R1←[R13]
;R2←[R13+4]
;R3←[R13+8]
;R4←[R13+12]
该指令的后缀IA表示在每次执行完加载/存储操作后,Rn按字长度增加,因此,指令可将连续存储单元的值传送到R1~R4。
指令中寄存器和内存单元的对应关系:编号低的寄存器对应于内存中低地址单元,编号高的寄存器对应于内存中高地址单元。
堆栈寻址
堆栈是一种数据结构,按先进后出(First In Last Out,FILO)的方式工作,使用一个称作堆栈指针的专用寄存器指示当前的操作位置,堆栈指针总是指向栈顶。
当堆栈指针指向最后压入堆栈的数据时,称为满堆栈(Full Stack),而当堆栈指针指向下一个将要放入数据的空位置时,称为空堆栈(Empty Stack)。
同时,根据堆栈的生成方式,又可以分为递增堆栈(Ascending Stack)和递减堆栈(Decending Stack),当堆栈由低地址向高地址生成时,称为递增堆栈,当堆栈由高地址向低地址生成时,称为递减堆栈。这样就有四种类型的堆栈工作方式,ARM微处理器支持这四种类型的堆栈工作方式,即:
满递增堆栈 (FA):堆栈指针指向最后压入的数据,且由低地址向高地址生成。
满递减堆栈(FD) :堆栈指针指向最后压入的数据,且由高地址向低地址生成。
空递增堆栈(EA) :堆栈指针指向下一个将要放入数据的空位置,且由低地址向高地址生成。
空递减堆栈(ED) :堆栈指针指向下一个将要放入数据的空位置,且由高地址向低地址生成。
块拷贝寻址
多寄存器传送指令用于将一块数据从存储器的某一位置拷贝到另一位置。 如:STMIA R0!,{R1-R7} ; 将R1~R7的数据保存到存储器中。
IA (increment after) 事后递增方式
IB (increment before) 事先递增方式
DA (decrement after) 事后递减方式
DB (decrement before) 事先递减方式
批量load/store指令可以实现在一组寄存器和一块连续的内存单元之间传输数据。例如:
LDMIA R13,{R5-R8} ;将内存单元(R13)到(R13+12)4个数据读取到R5-R8的4个寄存器中。
相对寻址
与基址变址寻址方式相类似,相对寻址是基址寻址的一种变通。
相对寻址以程序计数器PC的当前值为基地址,指令中的地址标号作为偏移量,将两者相加之后得到操作数的有效地址。以下程序段完成子程序的调用和返回,跳转指令BL采用了相对寻址方式:
BL NEXT ;跳转到子程序NEXT处执行
……
NEXT
……
MOV PC,LR ;从子程序返回
5、ARM微处理器的指令系统 算术指令
ARM指令集
ARM指令集的六大类指令进行详细的描述
跳转指令
数据处理指令
Load/store指令
程序状态寄存器传输指令
协处理器指令
异常中断产生指令
指令可选后缀- S后缀
S后缀的含义:
使用S后缀时,指令执行后程序状态寄存器的条件标志位将刷新;如:ADDS R3,R5,R8
不使用S后缀时,指令执行后程序状态寄存器的条件标志位将不发生变化。如:ADD R3,R5,R8
S后缀的使用范围:
有些指令不需要加S后缀,在执行时同样可以刷新条件标志位;如:CMP, TEQ, TST等。
有些指令不会引起条件标志位的变化,如:STR R5, [R7]
S后缀的使用目的:
在需要的时候,对条件进行测试。
在书写时,S后缀紧跟在指令助记符后面。
指令可选后缀- !后缀
!后缀的含义:
在指令的地址表达式中含有!后缀时,指令执行后,基址寄存器中的地址将发生变化,变化的结果如下:
基址寄存器中的地址值(指令执行后)= 指令执行前的值+地址偏移量
如果指令不含!后缀,则地址值不会发生变化。
!后缀的位置和范围:
!后缀必须紧跟在表达地址的表达式后面,而地址表达式要有明确的地址偏移量;
!后缀不能用在R15的后面;
当使用在单个地址寄存器后面时,必须确信这个寄存器有隐性的偏移量,如:STMDB R1!, {R3,R14}
指令可选后缀- B后缀/ H后缀
B后缀的含义:
指令所涉及的数据是一字节,不是一字或半字。如:LDRB R0, [R1,#4]
B后缀的位置:
B后缀紧跟在指令助记符后面。
H后缀的含义:
指令所涉及的数据是二字节,不是一字。如:LDRH R0, [R1,#4]
H后缀的位置:
H后缀紧跟在指令助记符后面。
指令可选后缀- T后缀
T后缀的含义:
指令在特权模式下对存储器的访问,将被存储器看成是用户模式的访问。
T后缀的限制:
一般只用在字传送和无符号字节传送中;
在用户模式下不可选用,选用是没有意义的;
不能与事先更新寻址一起使用
指令可选后缀- 条件后缀
条件后缀的定义:
如果满足后缀条件,则执行本条指令;否则不执行本条指令。
条件后缀只是影响指令的是否执行,不影响指令的内容。
条件后缀的说明:
条件后缀的含义为满足则执行,不满足则不执行;
被测试条件位有Z、C、N和V;
条件后缀共有15种,其编码称条件码,为4位代码;
在指令代码中,条件码排列在最高4位[31:28];
在汇编语言中,条件码助记符紧接在指令助记符后面;
无条件后缀AL应该省略不用。
条件后缀和S后缀的关系:
如果既选条件后缀也选S后缀,则书写中“S”排列在后面;
条件后缀是要测试条件标志位,而S后缀是要刷新条件标志位;
条件后缀要测试的是指令执行前的标志位,而S后缀是依据指令执行的结果改变条件标志。
跳转指令
跳转指令用于实现程序流程的跳转,在ARM程序中有两种方法可以实现程序流程的跳转:
使用专门的跳转指令。
直接向程序计数器PC写入跳转地址值。
通过向程序计数器PC写入跳转地址值,可以实现在4GB的地址空间中的任意跳转,在跳转之前结合使用
MOV LR,PC
等类似指令,可以保存将来的返回地址值,从而实现在4GB连续的线性地址空间的子程序调用。
ARM指令集中的跳转指令可以完成从当前指令向前或向后的32MB的地址空间的跳转,包括以下4条指令:
B 跳转指令
BL 带返回的跳转指令
BLX 带返回和状态切换的跳转指令(ARM7不支持)
BX 带状态切换的跳转指令
1、 B指令
B指令的格式为:
B{条件} 目标地址
B指令是最简单的跳转指令。一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的目标地址,从那里继续执行。
注意存储在跳转指令中的实际值是相对当前PC值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是 24 位有符号数,有符号扩展为 32 位后左移两位,表示的有效偏移为 26 位(前后32MB的地址空间)。
2、 BL指令
BL指令的格式为:
BL{条件} 目标地址
BL 是另一个跳转指令,但跳转之前,会在寄存器R14中保存PC的当前内容,因此,可以通过将R14 的内容重新加载到PC中,来返回到跳转指令之后的那个指令处执行。
以下指令:
BL Label ;当程序无条件跳转到标号Label处执行时,同 时将当前的PC值保存到R14中。
3、 BLX指令
BLX指令的格式为:
BLX 目标地址
BLX 目标地址指令从ARM指令集跳转到指令中所指定的目标地址,并将处理器的工作状态有ARM状态切换到Thumb状态,该指令同时将PC的当前内容保存到寄存器R14中。
因此,当子程序使用Thumb指令集,而调用者使用ARM指令集时,可以通过BLX指令实现子程序的调用和处理器工作状态的切换。同时,子程序的返回可以通过将寄存器R14值复制到PC中来完成。
本指令属于无条件执行的指令。
从ARM到Thumb的状态切换,并可以通过BX R14返回。
BLX指令的格式为:
BLX{条件}
BLX{条件} 指令跳转到指令中所指定的目标地址,目标地址处的指令既可以是ARM指令,也可以是Thumb指令。目标地址处的指令类型由寄存器的bit[0]决定。
从ARM到ARM或Thumb的状态切换。
指令操作的伪代码:
4、 BX指令
BX指令的格式为:
BX{条件}
BX指令跳转到指令中所指定的目标地址,目标地址处的指令既可以是ARM指令,也可以是Thumb指令。
目标地址处的指令类型由寄存器的bit[0]决定。
指令操作的伪代码:
三种子程序的返回方法:
MOV PC, R14
BX R14
当子程序入口中使用了
STMFD R13!, {,R14}时,可以用指令
LDMFD R13!, {,PC}返回
数据处理指令
数据处理指令可分为数据传送指令、算术逻辑运算指令和比较指令等。
数据传送指令用于在寄存器和第二个操作数之间进行数据的传输。
算术逻辑运算指令完成常用的算术与逻辑的运算,该类指令不但将运算结果保存在目的寄存器中,同时更新CPSR中的相应条件标志位。
比较指令不保存运算结果,只更新CPSR中相应的条件标志位。
算术指令: ADD ADC SUB SBC RSB RSC
逻辑指令: AND ORR EOR BIC
比较指令: CMP CMN TST TEQ
数据搬移: MOV MVN
上述指令只能对寄存器操作,不能针对存储器。
语法:
<操作>{<cond>}{S} Rd, Rn, Operand2
比较指令影响标志位 -不指定Rd
数据搬移不指定Rn
第二个操作数通过桶型移位器送到ALU中
1、 MOV指令
MOV指令的格式为:
MOV{条件}{S} 目的寄存器,源操作数
MOV指令可完成从另一个寄存器、被移位的寄存器或将一个立即数加载到目的寄存器。
其中S选项决定指令的操作是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。
当PC作为目标寄存器且指令中S位被置位时,指令在执行跳转操作的同时,将当前处理器模式的SPSR内容复制到CPSR中。
2、 MVN指令
MVN指令的格式为:
MVN{条件}{S} 目的寄存器,源操作数
MVN指令可完成从另一个寄存器、被移位的寄存器、或将一个立即数加载到目的寄存器。
与MOV指令不同之处是在传送之前按位被取反了,即把一个被取反的值传送到目的寄存器中。
其中S决定指令的操作是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。
3、 CMP指令
CMP指令的格式为:
CMP{条件} 操作数1,操作数2
CMP指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行比较,同时更新CPSR中条件标志位的值。
该指令进行一次减法运算,但不存储结果,只更改条件标志位。标志位表示的是操作数1与操作数2的关系(大、小、相等),例如,当操作数1大于操作操作数2,则此后的有GT 后缀的指令将可以执行。
4、 CMN指令
CMN指令的格式为:
CMN{条件} 操作数1,操作数2
CMN指令用于把一个寄存器的内容和另一个寄存器的内容或立即数取反后进行比较,同时更新CPSR中条件标志位的值。
该指令实际完成操作数1和操作数2相加,并根据结果更改条件标志位。
5、 TST指令
TST指令的格式为:
TST{条件} 操作数1,操作数2
TST指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位与运算,并根据运算结果更新CPSR中条件标志位的值。
操作数1是要测试的数据,而操作数2是一个位掩码,该指令一般用来检测是否设置了特定的位。
6、 TEQ指令
TEQ指令的格式为:
TEQ{条件} 操作数1,操作数2
TEQ指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位异或运算,并根据运算结果更新CPSR中条件标志位的值。
7、 ADD指令
ADD指令的格式为:
ADD{条件}{S} 目的寄存器,操作数1,操作数2
ADD指令用于把两个操作数相加,并将结果存放到目的寄存器中。
操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。
8、 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 ; 加第四个字,带进位
9、 SUB指令
SUB指令的格式为:
SUB{条件}{S} 目的寄存器,操作数1,操作数2
SUB指令用于把操作数1减去操作数2,并将结果存放到目的寄存器中。
操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。
该指令可用于有符号数或无符号数的减法运算。
10、SBC指令
SBC指令的格式为:
SBC{条件}{S} 目的寄存器,操作数1,操作数2
SBC指令用于把操作数1减去操作数2,再减去CPSR中的C条件标志位的反码,并将结果存放到目的寄存器中。
操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。
该指令使用进位标志来表示借位,这样就可以做大于32位的减法,注意不要忘记设置S后缀来更改进位标志。
该指令可用于有符号数或无符号数的减法运算。
11、RSB指令
RSB指令的格式为:
RSB{条件}{S} 目的寄存器,操作数1,操作数2
RSB指令称为逆向减法指令,用于把操作数2减去操作数1,并将结果存放到目的寄存器中。
操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。
该指令可用于有符号数或无符号数的减法运算。
12、RSC指令
RSC指令的格式为:
RSC{条件}{S} 目的寄存器,操作数1,操作数2
RSC指令用于把操作数2减去操作数1,再减去CPSR中的C条件标志位的反码,并将结果存放到目的寄存器中。
操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。
该指令使用进位标志来表示借位,这样就可以做大于32位的减法,注意不要忘记设置S后缀来更改进位标志。
该指令可用于有符号数或无符号数的减法运算。
13、AND指令
AND指令的格式为:
AND{条件}{S} 目的寄存器,操作数1,操作数2
AND指令用于在两个操作数上进行逻辑与运算,并把结果放置到目的寄存器中。
操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。
该指令常用于屏蔽操作数1的某些位。
14、ORR指令
ORR指令的格式为:
ORR{条件}{S} 目的寄存器,操作数1,操作数2
ORR指令用于在两个操作数上进行逻辑或运算,并把结果放置到目的寄存器中。
操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。
该指令常用于设置操作数1的某些位。
15、EOR指令
EOR指令的格式为:
EOR{条件}{S} 目的寄存器,操作数1,操作数2
EOR指令用于在两个操作数上进行逻辑异或运算,并把结果放置到目的寄存器中。
操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。
该指令常用于反转操作数1的某些位
16、BIC指令
BIC指令的格式为:
BIC{条件}{S} 目的寄存器,操作数1,操作数2
BIC指令用于清除操作数1的某些位,并把结果放置到目的寄存器中。
操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。
操作数2为32位的掩码,如果在掩码中设置了某一位,则清除这一位,未设置的掩码位保持不变。
乘法指令与乘加指令
ARM微处理器支持的乘法指令与乘加指令共有6条,可分为运算结果为32位和运算结果为64位两类,与前面的数据处理指令不同:
指令中的所有操作数、目的寄存器必须为通用寄存器,不能对操作数使用立即数或被移位的寄存器;
同时,目的寄存器和操作数1必须是不同的寄存器。
乘法指令与乘加指令共有以下6条:
MUL 32位乘法指令
MLA 32位乘加指令
SMULL 64位有符号数乘法指令
SMLAL 64位有符号数乘加指令
UMULL 64位无符号数乘法指令
UMLAL 64位无符号数乘加指令
1、 MUL指令
MUL指令的格式为:
MUL{条件}{S} 目的寄存器,操作数1,操作数2
MUL指令完成将操作数1与操作数2的乘法运算,并把结果放置到目的寄存器中,同时可以根据运算结果设置CPSR中相应的条件标志位。
其中,操作数1和操作数2均为32位的有符号数或无符号数。
2、 MLA指令
MLA指令的格式为:
MLA{条件}{S} 目的寄存器, 操作数1,操作数2,操作数3
MLA指令完成将操作数1与操作数2的乘法运算,再将乘积加上操作数3,并把结果放置到目的寄存器中,同时可以根据运算结果设置CPSR中相应的条件标志位。
其中,操作数1和操作数2均为32位的有符号数或无符号数。
3、 SMULL指令
SMULL指令的格式为:
SMULL{条件}{S} 目的寄存器Low,目的寄存器低High,操作数1,操作数2
SMULL指令完成将操作数1与操作数2的乘法运算,并把结果的低32位放置到目的寄存器Low中,结果的高32位放置到目的寄存器High中,同时可以根据运算结果设置CPSR中相应的条件标志位。
其中,操作数1和操作数2均为32位的有符号数。
4、 SMLAL指令
SMLAL指令的格式为:
SMLAL{条件}{S} 目的寄存器Low,目的寄存器低High,操作数1,操作数2
SMLAL指令完成将操作数1与操作数2的乘法运算,并把结果的低32位同目的寄存器Low中的值相加后又放置到目的寄存器Low中,结果的高32位同目的寄存器High中的值相加后又放置到目的寄存器High中,同时可以根据运算结果设置CPSR中相应的条件标志位。
其中,操作数1和操作数2均为32位的有符号数。
对于目的寄存器Low,在指令执行前存放64位加数的低32位,指令执行后存放结果的低32位。
对于目的寄存器High,在指令执行前存放64位加数的高32位,指令执行后存放结果的高32位。
6、ARM微处理器的指令系统 - 特殊指令
程序状态寄存器访问指令
ARM微处理器支持程序状态寄存器访问指令,用于在程序状态寄存器和通用寄存器之间传送数据,程序状态寄存器访问指令包括以下两条:
MRS 程序状态寄存器到通用寄存器的数据传送指令
MSR 通用寄存器到程序状态寄存器的数据传送指令
1、 MRS指令
MRS指令的格式为:
MRS{条件} 通用寄存器,程序状态寄存器(CPSR或SPSR)
MRS指令用于将程序状态寄存器的内容传送到通用寄存器中。
该指令一般用在以下几种情况:
当需要改变程序状态寄存器的内容时,可用MRS将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器。
当在异常处理或进程切换时,需要保存程序状态寄存器的值,可先用该指令读出程序状态寄存器的值,然后保存。
2、MSR指令
MSR指令的格式为:
MSR{条件} 程序状态寄存器(CPSR或SPSR)_<域>,操作数
MSR指令用于将操作数的内容传送到程序状态寄存器的特定域中。
其中,操作数可以为通用寄存器或立即数。
<域>用于设置程序状态寄存器中需要操作的位,32位的程序状态寄存器可分为4个域:
位[31:24]为条件标志位域,用f表示;
位[23:16]为状态位域,用s表示;
位[15:8]为扩展位域,用x表示;
位[7:0]为控制位域,用c表示;
该指令通常用于恢复或改变程序状态寄存器的内容,在使用时,一般要在MSR指令中指明将要操作的域。
用户模式下,所有位均可以被读取,但只有条件标志位 (_f)可被写。
指令示例:
MSR CPSR_c,R0 ;传送R0的内容到CPSR ,但仅 仅修改CPSR中的控制位域
MSR SPSR_f,R0 ;传送R0的内容到SPSR ,但仅 仅修改SPSR中的条件标志位域
加载/存储指令
ARM微处理器支持加载/存储指令用于在寄存器和存储器之间传送数据,加载指令用于将存储器中的数据传送到寄存器,存储指令则完成相反的操作。常用的加载存储指令如下:
LDR 字数据加载指令
LDRB 字节数据加载指令
LDRH 半字数据加载指令
STR 字数据存储指令
STRB 字节数据存储指令
STRH 半字数据存储指令
1、LDR指令
LDR指令的格式为:
LDR{条件} 目的寄存器,<存储器地址>
LDR指令用于从存储器中将一个32位的字数据传送到目的寄存器中。
该指令通常用于从存储器中读取32位的字数据到通用寄存器,然后对数据进行处理。
当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。
该指令在程序设计中比较常用,且寻址方式灵活多样。
LDR R0,[R1] ;将存储器地址为R1的字数据读入寄存 器R0。
LDR R0,[R1,R2] ;将存储器地址为R1+R2的字数据读入 寄存器R0。
LDR R0,[R1,#8] ;将存储器地址为R1+8的字数据读入 寄存器R0。
LDR R0,[R1,R2] ! ;将存储器地址为R1+R2的字数据读入 寄存器R0,并将新地址R1+R2写入R1。
LDR R0,[R1,#8] ! ;将存储器地址为R1+8的字数据读入 寄存器R0,并将新地址R1+8写入R1。
LDR R0,[R1],R2 ;将存储器地址为R1的字数据读入寄存器 R0,并将新地址R1+R2写入R1。
LDR R0,[R1,R2,LSL#2]! ;将存储器地址为R1+R2×4 的字数据读入寄存器R0,并将新地址R1+R2×4写入R1。
LDR R0,[R1],R2,LSL#2 ;将存储器地址为R1的字数据 读入寄存器R0,并将新地址R1+R2×4写入R1。
为允许装载大常数,汇编器提供了一条伪指令:
LDR rd, =const
它可能汇编成下列指令:
MOV or MVN。
或
LDR 指令,从数据池(Literal pools)读取常数。
For example
LDR r0,=0xFF => MOV r0,#0xFF
LDR r0,=0x55555555 => LDR r0,[PC,#Imm12] … … DCD 0x55555555
推荐使用这种方法把常数装入寄存器 。
地址访问
LDR/STR访问的地址由基址寄存器加上偏移量来产生。
针对word和无符号byte 的访问, 偏移量可以是:
一个无符号12-bit立即数 (如 0 - 4095 bytes). LDR r0,[r1,#8]
一个寄存器,或再加上移位(由立即数指定) LDR r0,[r1,r2] LDR r0,[r1,r2,LSL#2]
可以是从基址寄存器上加或减去偏移量: LDR r0,[r1,#-8] LDR r0,[r1,-r2] LDR r0,[r1,-r2,LSL#2]
对于halfword和带符号的halfword / byte, 偏移量可以是:
一个无符号8 bit 立即数 (如 0-255 bytes).
一个寄存器 (不能偏移)。
可选择采用pre-indexed或post-indexed方式寻址
2、LDRB指令
LDRB指令的格式为:
LDR{条件}B 目的寄存器,<存储器地址>
LDRB指令用于从存储器中将一个8位的字节数据传送到目的寄存器中,同时将寄存器的高24位清零。
该指令通常用于从存储器中读取8位的字节数据到通用寄存器,然后对数据进行处理。
当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。
3、LDRH指令
LDRH指令的格式为:
LDR{条件}H 目的寄存器,<存储器地址>
LDRH指令用于从存储器中将一个16位的半字数据传送到目的寄存器中,同时将寄存器的高16位清零。
该指令通常用于从存储器中读取16位的半字数据到通用寄存器,然后对数据进行处理。
当程序计数器PC作为目的寄存器时,指令从存储器中读取的字数据被当作目的地址,从而可以实现程序流程的跳转。
4、STR指令
STR指令的格式为:
STR{条件} 源寄存器,<存储器地址>
STR指令用于从源寄存器中将一个32位的字数据传送到存储器中。
该指令在程序设计中比较常用,且寻址方式灵活多样,使用方式可参考指令LDR。
5、STRB指令
STRB指令的格式为:
STR{条件}B 源寄存器,<存储器地址>
STRB指令用于从源寄存器中将一个8位的字节数据传送到存储器中。
该字节数据为源寄存器中的低8位。
6、STRH指令
STRH指令的格式为:
STR{条件}H 源寄存器,<存储器地址>
STRH指令用于从源寄存器中将一个16位的半字数据传送到存储器中。
该半字数据为源寄存器中的低16位。
批量数据加载/存储指令
ARM微处理器所支持批量数据加载/存储指令可以一次在一片连续的存储器单元和多个寄存器之间传送数据,批量加载指令用于将一片连续的存储器中的数据传送到多个寄存器,批量数据存储指令则完成相反的操作。常用的加载存储指令如下:
LDM 批量数据加载指令
STM 批量数据存储指令
LDM(或STM)指令的格式为:
LDM(或STM){条件}{类型} 基址寄存器{!},寄存器列表{∧}
LDM(或STM)指令用于从由基址寄存器所指示的一片连续存储器到寄存器列表所指示的多个寄存器之间传送数据,该指令的常见用途是将多个寄存器的内容入栈或出栈。其中,{类型}为以下几种情况:
IA 每次传送后地址加1;
IB 每次传送前地址加1;
DA 每次传送后地址减1;
DB 每次传送前地址减1;
FD 满递减堆栈;
ED 空递减堆栈;
FA 满递增堆栈;
EA 空递增堆栈;
{!}为可选后缀,若选用该后缀,则当数据传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。
基址寄存器不允许为R15,寄存器列表可以为R0~R15的任意组合。
{∧}为可选后缀,当指令为LDM且寄存器列表中包含R15,选用该后缀时表示:除了正常的数据传送之外,还将SPSR复制到CPSR。同时,该后缀还表示传入或传出的是用户模式下的寄存器,而不是当前模式下的寄存器。
LDM / STM 操作
语法:
<LDM|STM>{}<addressing_mode> Rb{!}, <寄存器 list>
4 中寻址操作:
LDMIA / STMIA Increment After(先操作,后增加)
LDMIB / STMIB Increment Before(先增加,后操作)
LDMDA / STMDA Decrement After (先操作,后递减)
LDMDB / STMDB Decrement Before (先递减,后操作)
EX.
LDMxx r10, {r0,r1,r4}
STMxx r10, {r0,r1,r4}
存储器块拷贝
可选项“ ! ”将导致LDM / STM 指令去自动更新基址寄存器
后缀为IA, IB时,加上4 乘以 用于传送的寄存器的数目的值
后缀为DA, DB时,减去4乘以用于传送的寄存器的数目的值
示例:
; r12指向源数据起始地址
; r14指向源数据尾地址
; r13指向目的数据起始地址
Loop LDMIA r12!, {r0-r11} ; 装载48 bytes
STMIA r13!, {r0-r11} ;和存储them
CMP r12, r14 ; check for the end
BNE loop ;和loop until done
此循环传送 48 bytes占用了31周期
时钟为33 MHz时传输速率超过50 Mbytes/sec
数据交换指令
ARM微处理器所支持数据交换指令能在存储器和寄存器之间交换数据。数据交换指令有如下两条:
SWP 字数据交换指令
SWPB 字节数据交换指令
1、SWP指令
SWP指令的格式为:
SWP{条件} 目的寄存器,源寄存器1,[源寄存器2]
SWP指令用于将源寄存器2所指向的存储器中的字数据传送到目的寄存器中,同时将源寄存器1中的字数据传送到源寄存器2所指向的存储器中。
显然,当源寄存器1和目的寄存器为同一个寄存器时,指令交换该寄存器和存储器的内容。
指令示例:
SWP R0,R1,[R2] ;将R2所指向的存储器中的字数 据传送到R0,同时将R1中的字数据传送到R2所指向 的存储单元。
SWP R0,R0,[R1] ;该指令完成将R1所指向的存储 器中的字数据与R0中的字数据交换。
在寄存器和存储器之间,由一次存储器读和一次存储器写组成的原子操作,完成一个字节或字的交换。
语法:
SWP{}{B} Rd, Rm, [Rn]
可用作信号量
不能由armcc编译产生,必须使用汇编器。
2、SWPB指令
SWPB指令的格式为:
SWP{条件}B 目的寄存器,源寄存器1,[源寄存器2]
SWPB指令用于将源寄存器2所指向的存储器中的字节数据传送到目的寄存器中,目的寄存器的高24清零,同时将源寄存器1中的字节数据传送到源寄存器2所指向的存储器中。
显然,当源寄存器1和目的寄存器为同一个寄存器时,指令交换该寄存器和存储器的内容。
移位指令(操作)
ARM微处理器内嵌的桶型移位器(Barrel Shifter),支持数据的各种移位操作。
移位操作在ARM指令集中不作为单独的指令使用,它只能作为指令格式中是一个字段,在汇编语言中表示为指令中的选项。
例如,数据处理指令的第二个操作数为寄存器时,就可以加入移位操作选项对它进行各种移位操作。
移位操作包括如下6种类型,ASL和LSL是等价的,可以自由互换:
LSL 逻辑左移
LSR 逻辑右移
ASL 算术左移
ASR 算术右移
ROR 循环右移
RRX 带扩展的循环右移
1、LSL(或ASL)操作
LSL(或ASL)操作的格式为:
通用寄存器,LSL(或ASL) 操作数
LSL(或ASL)可完成对通用寄存器中的内容进行逻辑(或算术)的左移操作,按操作数所指定的数量向左移位,低位用零来填充。其中,操作数可以是通用寄存器,也可以是立即数(0~31)。
操作示例:
MOV R0, R1, LSL#2 ;将R1中的内容左移两位后传送 到R0中。
2、LSR操作
LSR操作的格式为:
通用寄存器,LSR 操作数
LSR可完成对通用寄存器中的内容进行右移的操作,按操作数所指定的数量向右移位,左端用零来填充。其中,操作数可以是通用寄存器,也可以是立即数(0~31)。
操作示例:
MOV R0, R1, LSR#2 ;将R1中的内容右移两位后传送 到R0中,左端用零来填充。
3、ASR操作
ASR操作的格式为:
通用寄存器,ASR 操作数
ASR可完成对通用寄存器中的内容进行右移的操作,按操作数所指定的数量向右移位,左端用第31位的值来填充。其中,操作数可以是通用寄存器,也可以是立即数(0~31)。
操作示例:
MOV R0, R1, ASR#2 ;将R1中的内容右移两位后传送 到R0中,左端用第31位的值来填充。
4、ROR操作
ROR操作的格式为:
通用寄存器,ROR 操作数
ROR可完成对通用寄存器中的内容进行循环右移的操作,按操作数所指定的数量向右循环移位,左端用右端移出的位来填充。其中,操作数可以是通用寄存器,也可以是立即数(0~31)。显然,当进行32位的循环右移操作时,通用寄存器中的值不改变。
操作示例:
MOV R0, R1, ROR#2 ;将R1中的内容循环右移两位 后传送到R0中。
5、RRX操作
RRX操作的格式为:
通用寄存器,RRX 操作数
RRX可完成对通用寄存器中的内容进行带扩展的循环右移的操作,按操作数所指定的数量向右循环移位,左端用进位标志位C来填充。其中,操作数可以是通用寄存器,也可以是立即数(0~31)。
操作示例:
MOV R0, R1, RRX #2 ;将R1中的内容进行带扩 展的循环右移两位后传送到R0中。
7、伪指令
在ARM汇编语言程序里,有一些特殊指令助记符,这些助记符与指令系统的助记符不同,没有相对应的操作码,通常称这些特殊指令助记符为伪指令,他们所完成的操作称为伪操作。
伪指令在源程序中的作用是为完成汇编程序作各种准备工作的,这些伪指令仅在汇编过程中起作用,一旦汇编结束,伪指令的使命就完成。
伪指令的两个基本特征:
伪指令是一条指令;
伪指令不是一条真正的指令,通常没有指令代码。
在ARM的汇编程序中,有如下几种伪指令:
符号定义伪指令
数据定义伪指令
汇编控制伪指令
宏指令
其他伪指令
符号定义(Symbol Definition)伪指令
符号定义伪指令用于定义ARM汇编程序中的变量、对变量赋值以及定义寄存器的别名等操作。常见的符号定义伪指令有如下几种:
用于定义全局变量的GBLA、GBLL和GBLS。
用于定义局部变量的LCLA、LCLL和LCLS。
用于对变量赋值的SETA、SETL、SETS。
为通用寄存器列表定义名称的RLIST。
- GBLA、GBLL和GBLS
语法格式:
GBLA(GBLL或GBLS) 全局变量名
GBLA、GBLL和GBLS伪指令用于定义一个ARM程序中的全局变量,并将其初始化。其中:
GBLA伪指令用于定义一个全局的数字变量,并初始化为0;
GBLL伪指令用于定义一个全局的逻辑变量,并初始化为F(假);
GBLS伪指令用于定义一个全局的字符串变量,并初始化为空;
由于以上三条伪指令用于定义全局变量,因此在整个程序范围内变量名必须唯一。
RLIST
语法格式:
名称 RLIST {寄存器列表}
RLIST伪指令可用于对一个通用寄存器列表定义名称,使用该伪指令定义的名称可在ARM指令LDM/STM中使用。
在LDM/STM指令中,列表中的寄存器访问次序为根据寄存器的编号由低到高,而与列表中的寄存器排列次序无关。
使用示例:
RegList RLIST {R0-R5,R8,R10}
;将寄存器列表名称定义为RegList,
;可在ARM指令LDM/STM中通过
;该名称访问寄存器列表。
数据定义(Data Definition)伪指令
数据定义伪指令一般用于为特定的数据分配存储单元,同时可完成已分配存储单元的初始化。常见的数据定义伪指令有如下几种:
DCB 用于分配一片连续的字节存储单元并用指定 的数据初始化。
DCW(DCWU)用于分配一片连续的半字存储单元并用指定的 数据初始化。
DCD(DCDU) 用于分配一片连续的字存储单元并用指定的数 据初始化。
DCFD(DCFDU) 用于为双精度的浮点数分配一片连续的字存 储单元并用指定的数据初始化。
DCFS(DCFSU)用于为单精度的浮点数分配一片连续的字存 储单元并用指定的数据初始化。
DCQ(DCQU)用于分配一片以8字节为单位的连续的存储单元 并用指定的数据初始化。
SPACE 用于分配一片连续的存储单元
MAP 用于定义一个结构化的内存表首地址
FIELD 用于定义一个结构化的内存表的数据域
SPACE
语法格式:
标号 SPACE 表达式
SPACE伪指令用于分配一片连续的存储区域并初始化为0。其中,表达式为要分配的字节数。
SPACE也可用“%”代替。
使用示例:
DataSpace SPACE 100
DataSpace % 100
;分配连续100字节的存储单元并初始化为0。
. MAP
语法格式:
MAP 表达式{,基址寄存器}
MAP伪指令用于定义一个结构化的内存表的首地址。
MAP也可用“^”代替。
表达式可以为程序中的标号或数学表达式,基址寄存器为可选项。
当基址寄存器选项不存在时,表达式的值即为内存表的首地址;
当该选项存在时,内存表的首地址为表达式的值与基址寄存器的和。
MAP伪指令通常与FIELD伪指令配合使用来定义结构化的内存表。
使用示例:
MAP 0x100,R0
^ 0x100,R0
;定义结构化内存表首地址的值为0x100+R0。
. FILED
语法格式:
标号 FIELD 表达式
FIELD伪指令用于定义一个结构化内存表中的数据域。
FILED也可用“#”代替。
表达式的值为当前数据域在内存表中所占的字节数。
FIELD伪指令常与MAP伪指令配合使用来定义结构化的内存表。MAP伪指令定义内存表的首地址,FIELD伪指令定义内存表中的各个数据域,并可以为每个数据域指定一个标号供其他的指令引用。
注意MAP和FIELD伪指令仅用于定义数据结构,并不实际分配存储单元。
使用示例:
MAP 0x100 ;定义结构化内存表首地址的值为0x100。
A FIELD 16 ;定义A的长度为16字节,位置为0x100
B # 32 ;定义B的长度为32字节,位置为0x110
S FIELD 256 ;定义S的长度为256字节,位置为0x130
汇编控制(Assembly Control)伪指令
汇编控制伪指令用于控制汇编程序的执行流程,常用的汇编控制伪指令包括以下几条:
IF、ELSE、ENDIF
WHILE、WEND
MACRO、MEND
MEXIT
IF、ELSE、ENDIF
语法格式:
IF 逻辑表达式
指令序列1
ELSE
指令序列2
ENDIF
IF、ELSE、ENDIF伪指令能根据条件的成立与否决定是否执行某个指令序列。当IF后面的逻辑表达式为真,则执行指令序列1,否则执行指令序列2。其中,ELSE及指令序列2可以没有,此时,当IF后面的逻辑表达式为真,则执行指令序列1,否则继续执行后面的指令。
IF、ELSE、ENDIF伪指令可以嵌套使用。
. CODE16、CODE32
语法格式:
CODE16(或CODE32)
CODE16伪指令通知编译器,其后的指令序列为16位的Thumb指令。
CODE32伪指令通知编译器,其后的指令序列为32位的ARM指令。
若在汇编源程序中同时包含ARM指令和Thumb指令时,可用CODE16伪指令通知编译器其后的指令序列为16位的Thumb指令,CODE32伪指令通知编译器其后的指令序列为32位的ARM指令。
因此,在使用ARM指令和Thumb指令混合编程的代码里,可用这两条伪指令进行切换,但注意他们只通知编译器其后指令的类型,并不能对处理器进行状态的切换。
注意:这两条伪指令并不能实现ARM状态的切换。
ENTRY
语法格式:
ENTRY
ENTRY伪指令用于指定汇编程序的入口点。在一个完整的汇编程序中至少要有一个ENTRY(也可以有多个,当有多个ENTRY时,程序的真正入口点由链接器指定),但在一个源文件里最多只能有一个ENTRY(可以没有)。
在只有一个入口时,编译程序会把这个入口的地址定义为系统复位后的程序起始点。
程序入口应该定义在源文件的第1条有效语句之前。
使用示例:
AREA Init,CODE,READONLY
ENTRY ;指定应用程序的入口点
……
. END
语法格式:
END
END伪指令用于通知编译器已经到了源程序的结尾。
使用示例:
AREA Init,CODE,READONLY
……
END ;指定应用程序的结尾
注意:END指令不是AREA段的结束。
. EQU
语法格式:
名称 EQU 表达式{,类型}
EQU伪指令用于为程序中的常量、标号等定义一个等效的字符名称,类似于C语言中的#define。
EQU可用“*”代替。
名称为EQU伪指令定义的字符名称,当表达式为32位的常量时,可以指定表达式的数据类型,可以有以下三种类型:
CODE16
CODE32
DATA
使用示例:
Test EQU 50 ;定义标号Test的值为50
Addr * 0x55,CODE32
;定义Addr的值为0x55,且该处为32位的ARM指令。
. EXPORT(或GLOBAL)
语法格式:
EXPORT 标号 {[WEAK]}
EXPORT伪指令用于在程序中声明一个全局的标号,该标号可在其他的文件中引用。
EXPORT可用GLOBAL代替。
标号在程序中区分大小写,[WEAK]选项声明其他的同名标号优先于该标号被引用。
使用示例:
AREA Init,CODE,READONLY
EXPORT Stest ;声明一个可全局引用的标号Stest
……
END
IMPORT
语法格式:
IMPORT 标号 {[WEAK]}
IMPORT伪指令用于通知编译器要使用的标号在其他的源文件中定义,但要在当前源文件中引用,而且无论当前源文件是否引用该标号,该标号均会被加入到当前源文件的符号表中。
标号在程序中区分大小写,[WEAK]选项表示当所有的源文件都没有定义这样一个标号时,编译器也不给出错误信息,在多数情况下将该标号置为0,若该标号为B或BL指令引用,则将B或BL指令置为NOP操作。
使用示例:
AREA Init,CODE,READONLY
IMPORT Main ;通知编译器当前文件要引用标号 ;Main,但Main在其他源文件中定义
……
END
EXTERN
语法格式:
EXTERN 标号{[WEAK]}
EXTERN伪指令用于通知编译器要使用的标号在其他的源文件中定义,但要在当前源文件中引用,如果当前源文件实际并未引用该标号,该标号就不会被加入到当前源文件的符号表中。
标号在程序中区分大小写,[WEAK]选项表示当所有的源文件都没有定义这样一个标号时,编译器也不给出错误信息,在多数情况下将该标号置为0,若该标号为B或BL指令引用,则将B或BL指令置为NOP操作。
使用示例:
AREA Init,CODE,READONLY
EXTERN Main ;通知编译器当前文件要引用标号Main,但 ;Main在其他源文件中定义
……
END
GET(或INCLUDE)
语法格式:
GET 文件名
GET伪指令用于将一个源文件包含到当前的源文件中,并将被包含的源文件在当前位置进行汇编处理。
可以使用INCLUDE代替GET。
汇编程序中常用的方法是在某源文件中定义一些宏指令,用EQU定义常量的符号名称,用MAP和FIELD定义结构化的数据类型,然后用GET伪指令将这个源文件包含到其他的源文件中。使用方法与C语言中的“include”相似。
GET伪指令只能用于包含源文件,包含目标文件需要使用INCBIN伪指令
使用示例:
AREA Init,CODE,READONLY
GET a1.s ;通知编译器当前源文件包含源文件a1.s
GET C:\a2.s ;通知编译器当前源文件包含源文件C:\ a2.s
……
END
几条特殊的伪指令
ADR (小范围的地址读取伪指令)
ADRL(中等范围的地址读取伪指令)
LDR(大范围的地址读取伪指令)
NOP(空操作伪指令)
ADR
语法格式
ADR {cond} 寄存器,表达式
在汇编编译器处理源程序时,ADR伪指令被编译器替换成一条合适的指令。
通常编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能。
ADR伪指令中的地址是基于PC或寄存器的,所以ADR读取到的地址与位置无关。
使用示例:
start MOV r0,#10
ADR r4,start ;本指令被替换成一条SUB指令
SUB r4,pc,#0xc
ADRL
语法格式
ADRL {cond} 寄存器,表达式
将基于PC或基于寄存器的地址值读取到寄存器中。
在汇编编译器处理源程序时,ADR伪指令被编译器替换成两条合适的指令。
使用示例:
start MOV r0,#10
ADRL r4,start +60000 ;本指令被替换成以下两条指令
ADD r4,pc,#0xe800
ADD r4,r4,#0x254
LDR 唯一一条ARM指令与伪指令同名的指令。
语法格式
LDR {cond} 寄存器,=[表达式|标号]
将一个32位的常数或者一个地址值读取到寄存器中。
当表达式表示的地址值没有超过MOV或MVN指令中地址的取值范围时,用合适的MOV或MVN指令来代替该指令;否则将标签表示的数值放在数据缓冲区中,同时用一条基于PC的LDR指令读取该数值。
使用示例:
LDR R1,=0xFF0 汇编后变换成:MOV R1,0xFF0
LDR R1,=0xFFFFFF00 汇编后变换成:
LDR R1,[PC,OFFSET_TO LPOOL]
……..
LPOOL DCD 0xFFFFFF00
NOP
语法格式
NOP
NOP伪指令将被替换成ARM中的空操作,如MOV R0,R0
NOP伪指令不影响CPSR中的条件标志位。
8、伪指令2
汇编语言的语句格式
ARM(Thumb)汇编语言的语句格式为:
{标号} {指令或伪指令} {;注释}
标号必须从一行的行头开始,并且符号中不能包含空格。
指令不能从一行的行头开始,即在一行语句中,指令的前面必须有空格或者标号。
在汇编语言程序设计中,每一条指令的助记符可以全部用大写、或全部用小写,但不允许在一条指令中大、小写混用。
寄存器可以大写或小写。
伪指令有些必须在一行的开头顶格书写,另外一些必须留有空格。
注释以分号“;”开头,到行末结束。
如果一条语句太长,可将该长语句分为若干行来书写,在行的末尾用“\”表示下一行与本行为同一条语句。
在源程序中,语句之间可以插入空行,增强可读性。
常数:数值、布尔值、字符或字符串
数字:十进制数、十六进制数
布尔值:{TRUE/FALSE}
字符:由左右单引号组成
字符串:由左右双引号括住多个字符或空格组成
汇编语言的源程序主要由指令、伪指令、语句标号和注释组成。
指令:一条指令一般是一个简短的汇编语句行,由指令助记符和操作数、操作寄存器或语句标号组成。
伪指令:
通过伪指令把设计意图表达给编译器,编译器依据这些伪指令,组织、编译和连接程序;
大多数伪指令在编译后都不留痕迹。
语句标号:语句标号的主要作用有两个:
一是表达地址;
二是为一段语句命名,以方便记忆和阅读。
注释:注释是为了方便阅读和记忆。
在汇编语言程序中常用的符号
在汇编语言程序设计中,经常使用各种符号代替地址、变量和常量等,以增加程序的可读性。
尽管符号的命名由编程者决定,但并不是任意的,必须遵循以下的约定:
符号由大小写字母、数字以及下划线组成;
局部标号以数字开头,其他的符号都不能以数字开头;
符号区分大小写,同名的大、小写符号会被编译器认为是两个不同的符号;
符号在其作用范围内必须唯一;
自定义的符号名不能与系统的保留字相同;
符号名不应与指令或伪指令同名。
程序中的变量
程序中的变量是指其值在程序的运行过程中可以改变的量。ARM(Thumb)汇编程序所支持的变量有数字变量、逻辑变量和字符串变量。
数字变量用于在程序的运行中保存数字值,但注意数字值的大小不应超出数字变量所能表示的范围。
逻辑变量用于在程序的运行中保存逻辑值,逻辑值只有两种取值情况:真{true}或假{false}。
字符串变量用于在程序的运行中保存一个字符串,但注意字符串的长度不应超出字符串变量所能表示的范围。
在ARM(Thumb)汇编语言程序设计中,可使用GBLA、GBLL、GBLS伪指令声明全局变量;使用LCLA、LCLL、LCLS伪指令声明局部变量;并可使用SETA、SETL和SETS对其进行初始化。
程序中的常量是指其值在程序的运行过程中不能被改变的量。ARM(Thumb)汇编程序所支持的常量有数字常量、逻辑常量和字符串常量。
数字常量一般为32位的整数,当作为无符号数时,其取值范围为0~232-1;当作为有符号数时,其取值范围为-231~231-1。
逻辑常量只有两种取值情况:真或假。
字符串常量为一个固定的字符串,一般用于程序运行时的信息提示。
使用EQU来定义数字常量。
程序中的变量替换
程序中的变量可通过替换操作取得一个常量。
替换操作符为“
”
。
如
果
在
数
字
变
量
前
面
有
一
个
代
换
操
作
符
“
”。 如果在数字变量前面有一个代换操作符“
”。如果在数字变量前面有一个代换操作符“”,编译器会将该数字变量的值转换为十六进制的字符串,并将该十六进制的字符串替换“
”
后
的
数
字
变
量
。
如
果
在
逻
辑
变
量
前
面
有
一
个
替
换
操
作
符
“
”后的数字变量。 如果在逻辑变量前面有一个替换操作符“
”后的数字变量。如果在逻辑变量前面有一个替换操作符“”,编译器会将该逻辑变量替换为它的取值(真或假)。
如果在字符串变量前面有一个替换操作符“
”
,
编
译
器
会
将
该
字
符
串
变
量
的
值
替
换
“
”,编译器会将该字符串变量的值替换“
”,编译器会将该字符串变量的值替换“”后的字符串变量。
使用示例:
LCLS S1 ;定义局部字符串变量S1和S2
LCLS S2
S1 SETS “Test!”
S2 SETS “This is a $S1”
;字符串变量S2的值为“This is a Test!”
标号
标号是表示程序中的指令或数据地址的符号,主要有三种:
基于PC的标号
是位于目标指令前或者程序中数据定义伪操作前的标号。
被处理成PC值加上或减去一个数字常量。
基于寄存器的标号
通常用MAP和FIELD伪操作定义,或用EQU伪操作定义。
被处理成寄存器的值加上或减去一个数字常量。
绝对地址
绝对地址是一个32位的数字量。
寻址范围为0~231-1,即可以寻址整个内存空间。
局部标号
局部标号主要在局部范围使用。
局部标号定义的语法格式:
N{routname}
N为0-99的数字,routname为当前作用范围的名称。
局部变量引用的语法格式:
%{F|B}{A|T} N{routname}
字符串表达式及运算符
字符串表达式一般由字符串常量、字符串变量、运算符和括号构成。编译器所支持的字符串最大长度为512字节。常用的与字符串表达式相关的运算符如下:
LEN运算符
LEN运算符返回字符串的长度(字符数),以X表示字符串表达式,其语法格式如下:
:LEN:X
CHR运算符
CHR运算符将0~255之间的整数转换为一个ASCII字符,以M表示某一个整数,其语法格式如下:
:CHR:M
STR运算符
STR运算符将将一个数字表达式或逻辑表达式转换为一个字符串。对于数字表达式,STR运算符将其转换为一个以十六进制组成的字符串;对于逻辑表达式,STR运算符将其转换为字符串T或F,其语法格式如下:
:STR:X
其中,X为一个数字表达式或逻辑表达式。
LEFT运算符
LEFT运算符返回某个字符串左端的一个子串,其语法格式如下:
X:LEFT:Y
其中:X为源字符串,Y为一个整数,表示要返回的字符个数。
RIGHT运算符
与LEFT运算符相对应,RIGHT运算符返回某个字符串右端的一个子串,其语法格式如下:
X:RIGHT:Y
其中:X为源字符串,Y为一个整数,表示要返回的字符个数。
CC运算符
CC运算符用于将两个字符串连接成一个字符串,其语法格式如下:
X:CC:Y
其中:X为源字符串1,Y为源字符串2,CC运算符将Y连接到X的后面。