【嵌入式系统】课程复习资料整理
一、绪论
1.定义
- 从技术的角度定义:以应用为中心、以计算机技术为基础、软件硬件可裁剪、对功能、可靠性、成本、体积、功耗严格要求的专用计算机系统。
- 从系统的角度定义:嵌入式系统是设计完成复杂功能的硬件和软件,并使其紧密耦合在一起的计算机系统。
- 术语嵌入式反映了这些系统通常是更大系统中的一个完整的部分,称为嵌入的系统。嵌入的系统中可以共存多个嵌入式系统。
2.嵌入式系统的特点
- 嵌入式系统中运行的任务是专用而确定的
- 嵌入式系统往往对实时性提出较高的要求,嵌入式系统中使用的操作系统一般是实时操作系统
- 嵌入式系统运行需要高可靠性保障,比桌面系统的故障容忍能力弱很多
- 嵌入式系统需要忍受长时间、无人值守条件下的运行
- 嵌入式系统运行的环境恶劣
- 嵌入式系统大都有功耗约束
- 嵌入式系统比桌面通用系统可用资源少得多,为降低系统成本,降低功耗,嵌入式系统的资源配置遵循够用就行!
- 嵌入式系统的开发需要专用工具和特殊方法
3.嵌入式系统结构
- 嵌入式系统一般由嵌入式微处理器、外围硬件设备、嵌入式操作系统(可选),以及用户的应用软件系统等四个部分组成
- 哈佛结构:指令和数据有各自的总线,执行效率高,设计复杂度高
- 冯诺依曼结构:存储程序原理,代码本身也是数据;简化了结构,降低了复杂性,总线的吞吐量成为性能提升的瓶颈
4.CISC(复杂指令集计算机)和RISC(精简指令集计算机)的特点
CISC(Complex Instruction Set Computer)复杂指令集计算机:
- 指令集复杂:CISC指令集具有复杂的指令,每个指令可以执行多个操作,包括访问内存、算术运算、逻辑运算等,这些指令通常需要多个时钟周期来完成。
- 少量通用寄存器:CISC架构通常包含少量通用寄存器
- 面向内存:CISC架构通常设计为面向内存,每个指令能够直接访问内存,不需要中间变量,可以更快地执行操作。
- 程序大小较小:由于CISC指令集具有复杂的指令,所以程序的大小相对较小,因为可以使用少量的指令来完成复杂的操作。
RISC(Reduced Instruction Set Computer)精简指令集计算机:
- 指令集精简:RISC指令集具有精简的指令,每个指令只能执行一个操作,通常只需要一个时钟周期就能完成。指令规整、对称、简单。指令小于100条,基本寻址方式有2~3种;指令字长度一致,单拍完成,便于流水操作;
- 大量通用寄存器:RISC架构通常只包含大量的通用寄存器
- 面向寄存器:RISC架构通常设计为面向寄存器,每个指令都需要中间变量,使得指令执行速度更快。
- 程序大小较大:由于RISC指令集具有精简的指令,所以程序的大小相对较大,需要使用更多的指令来完成复杂的操作。
5.嵌入式微处理器
- ARM:体积小、低功耗、低成本、高性能
- MIPS:无内部互锁流水级的微处理器,是一种处理器内核标准,基于RISC架构
- PowerPC:基于RISC架构
6.使用实时操作系统主要有以下几个因素
- 提高了系统的可靠性
- 提高了开发效率,缩短了开发周期
- 充分发挥了32位CPU的多任务潜力
7.嵌入式实时操作系统的优缺点
优点:
- 在嵌入式实时操作系统环境下开发实时应用程序使程序的设计和扩展变得容易,不需要大的改动就可以增加新的功能。
- 通过将应用程序分割成若干独立的任务模块,使应用程序的设计过程大为简化;而且对实时性要求苛刻的事件都得到了快速、可靠的处理。
- 通过有效的系统服务,嵌入式实时操作系统使得系统资源得到更好的利用。
缺点:
- 需要额外的ROM/RAM开销,2~5%的CPU额外负荷。
8.嵌入式操作系统
- uClinux
- Windows CE
- Android
- iOS
- VxWorks
- μC/OS-II
- eCos
二、ARM体系结构
1.IP核分类(根据IP核的提供方式分类)
- 软核:综合之前的RTL代码,只经过功能仿真,需要经过综合以及布局布线才能使用。
- 固核:完成软核的设计外,及门级电路综合和时序仿真等设计环节,以门级电路网表的形式提供给用户。
- 硬核:基于物理描述并经过工艺验证,提供给用户的形式是电路物理结构、掩模版图和全套工艺文件。
2.ARM微处理器特点
- 体积小、低功耗、低成本、高性能
- 支持Thumb(16位)/ARM(32位)双指令集
- 使用寄存器,指令执行速度更快
- 大多数数据操作都在寄存器中完成
- 寻址方式灵活简单,执行效率高
- 指令长度固定
3.ARM系列产品表示(以ARM 926EJ-S为例)
- 9表示Family number,7:ARM7、9:ARM9、10:ARM10、11:ARM11
- 2表示Memory system,2:Cache+MMU、4: Cache + MPU、 6: no cache,MMU/MPU
- 6表示Memory size,0: Cache size (4-128KB) 、6: TCM:Tightly Coupled Memory,紧耦合内存
- EJ表示Extensions ,E: DSP extension、 J: Jazelle extension 、T: Thumb support
- S表示Synthesizable
4.ARM7TDMI各字母含义(ARM7TDMI 之后的所有 ARM 内核,即使没有包含 “TDMI” 字符,也都默认包含了 TDMI 的功能特性)
- T:支持Thumb指令集
- D:片上调试,一个边界扫描链 JTAG,可使 CPU 进入调试模式
- M:快速乘法器,32位乘32位得到64位,32位的乘加得到64位
- I:Embedded ICE,嵌入式跟踪宏单元,用于实现断点观测及变量观测的逻辑电路部分。提供片上断点和调试点
- E:DSP指令,增加了DSP算法处理器指令:16位乘加指令,饱和的带符号数的加减法,双字数据操作,cache预取指令
- J:Java加速器Jazelle,提高java代码的运行速度
- S:可综合,提供VHDL或Verilog语言设计文件
5.AMBA总线体系结构(ARM微控制器使用的是AMBA总线体系结构)
- AHB总线(Advanced High-performance Bus):用于连接高性能系统模块。它支持突发数据传输方式及单个数据传输方式,所有时序参考同一个时钟沿。
- ASB总线(Advanced System Bus):用于连接高性能系统模块,在不必要使用AHB的高速特性的场合,它支持突发数据传输模式。
- APB总线(Advance Peripheral Bus):是一个简单接口支持低性能的外围接口。
- 3.0 引入AXI总线 (Advanced eXtensible Interface)
6.ARM7系列采用三级流水线
- 第一级取指:取指级的任务是从程序存储器中读取指令。
- 第二级译码:译码级完成对指令的解析,并为下一个周期准备数据路径需要的控制信号。由指令与译码逻辑完成,不占用数据通路。
- 第三级执行:执行完成指令要求的操作,并根据需要将结果写回目的寄存器。
7.ARM7单周期指令最佳流水线
8.ARM9具有5级流水线
9.ARM处理器有37(31+6)个物理寄存器,31个通用寄存器和6个状态寄存器
10.ARM指令集
ARM指令集可分为5大类指令,所有指令都可以条件执行,其中一些指令还可以根据执行结果更新CPSR寄存器的相关标志位.
- 数据处理指令:MOV, AND, SUB,ADD
- 加载和存储指令: LDR,STR,LDM,STM
- 分支指令: B, BX
- 协处理器指令: LDC, STC
- 杂项指令: SWI, MRS,MSR
11.Thumb指令集
16位Thumb指令集:是ARM指令集的子集,按16位指令重新编码,固定的16位指令
- 分支指令;
- 数据处理指令;
- 寄存器加载和存储指令;
- 异常产生指令。
12.ARM体系结构中的数据类型
- 字节(Byte):在ARM体系结构和8位/16位处理器体系结构中,字节的长度均为8位。
- 字(Word):在ARM体系结构中,字的长度为32位,必须分配为占用4个字节。
- 半字(Half-Word):在ARM体系结构中,半字的长度为16位,必须分配为占用两个字节。
13.ARM微处理器的工作状态
- ARM状态—处理器执行32位的字对齐的ARM指令,伪指令CODE32声明;
- Thumb状态—处理器执行16位的、半字对齐的Thumb指令,伪指令CODE16声明。
14.处理器状态切换
- 进入Thumb状态:当操作数寄存器的状态位==(位[0])为1时,执行BX(带状态切换分支指令)==进入Thumb状态。如果处理器在Thumb状态进入异常,则当异常处理返回时,自动转换到Thumb状态。
- 进入ARM状态:当操作数寄存器的状态位==(位[0])为0==时执行BX指令进入ARM状态。当处理器进行异常处理时,进入ARM状态,从异常向量地址处开始执行。
15.ARM体系结构的存储器格式
- ==大端格式(Big Endian)==字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中。
- ==小端格式(Little Endian)==低地址中存放的是字数据的低字节,高地址存放的是字数据的高字节。
- ARM默认小端格式,但用户可设置大、小端格式
16.处理器模式
处理器模式 | 说明 | 备注 |
---|---|---|
用户(usr) | 正常程序工作模式 | 不能直接切换到其它模式 |
系统(sys) | 用于支持操作系统的特权任务等 | 与用户模式类似,但具有可以直接切换到其他模式等特权 |
快中断(fiq) | 支持高速数据传输及通道处理 | FIQ异常响应时进入此模式 |
中断(irq) | 用于通用中断处理 | IRQ异常响应时进入此模式 |
管理(svc) | 操作系统保护代码 | 系统复位和软件中断响应时进入此模式 |
中止(abt) | 用于支持虚拟内存和/或存储器保护 | 预取中止和数据中止 |
未定义(und) | 支持硬件协处理器的软件仿真 | 未定义指令异常响应时进入此模式 |
- 除用户模式外,其他模式均为特权模式;特权模式可以自由地切换处理器模式,而用户模式不能直接切换到别的模式。
- 除用户模式和系统模式外,其它模式均为异常模式。它们除了可以通过程序切换进入外,也可以由特定的异常进入。
- 用户模式和系统模式使用完全相同的寄存器
17.寄存器组织
- ARM处理器有共37个寄存器,分成两大类:31个通用32位寄存器;6个状态寄存器。
- 寄存器R0~R13为保存数据或地址值的通用寄存器。
- R0~R7为未分组的寄存器,也就是说对于任何处理器模式,这些寄存器都对应于相同的32位物理寄存器。
- 寄存器R8~R14为分组寄存器。它们所对应的物理寄存器取决于当前的处理器模式,几乎所有允许使用通用寄存器的指令都允许使用分组寄存器
- 寄存器R13常作为堆栈指针(SP)
- R14为链接寄存器(LR),在结构上有两个特殊功能:
- 在每种模式下,模式自身的R14版本用于保存子程序返回地址;
- 当发生异常时,该模式下的R14被设置成该异常模式将要返回的地址。
- 寄存器R15为程序计数器(PC),它指向正在取指的地址。
- 正常操作时,从R15读取的值是处理器正在取指的地址,即当前正在执行指令的地址加上8个字节(两条ARM指令的长度)。
- 由于ARM指令总是以字为单位,所以R15寄存器的最低两位总是为0。
- 当使用STR或STM指令保存R15时,会有一个例外:这些指令可能将当前指令地址加8字节或加12字节保存(将来可能还有其它数字)。偏移量是8还是12取决于具体的ARM芯片
- 寄存器CPSR为程序状态寄存器;每种异常都有自己的SPSR,在因为异常事件而进入异常时它保存CPSR的当前值,异常退出时可通过它恢复CPSR。
- Thumb状态下的寄存器集是ARM状态集的子集,程序员可以直接访问的寄存器为:8个通用寄存器R0~R7;程序计数器(PC);堆栈指针(SP);链接寄存器(LR);有条件访问程序状态寄存器( CPSR)。
- 在发生异常时,处理器自动进入ARM状态。
- 在Thumb状态中,高寄存器(R8~R12)不是标准寄存器集的一部分。汇编语言程序员对它们的访问受到限制,但可以将它们用于快速暂存。只能使用MOV、CMP和ADD指令对高寄存器操作。
- CPSR反映了当前处理器的状态:4个条件码标志;2个中断控制位; 5个对当前处理器模式进行编码的位;1个指示当前执行指令的工作状态位;保留位
18.程序状态寄存器
- 保留位被保留将来使用。为了提高程序的可移植性,当改变CPSR标志和控制位时,请不要改变这些保留位。另外,请确保您程序的运行不受保留位的值影响,因为将来的处理器可能会将这些位设置为1或者0。
- 最低8位为控制位,当发生异常时,这些位被硬件改变。当处理器处于一个特权模式时,可用软件操作这些位。
- 当进行加法运算,并且发生有符号溢出时V=1,否则V=0,其它指令V通常不变。
- 当进行加法运算,并且最高位产生进位时C=1,否则C=0。当进行减法运算,并且最高位产生借位时C=1,否则C=0。对于移位操作指令,C为从最高位最后移出的值,其它指令C通常不变;
- 指令结果为0时Z=1(表示比较结果“相等”),否则Z=0
- 运算结果的最高位反映在该标志位。对于有符号二进制补码,结果为负数时N=1,结果为正数或零时N=0;
- 大多数“数值处理指令”可以选择是否影响条件代码标志位(指令带S后缀);但有些指令执行总是影响条件代码标志。 所有ARM指令都可按条件来执行,而Thumb指令中只有分支指令可按条件执行。
19.CPSR模式位设置表
M[4:0] | 模式 |
---|---|
10000 | 用户 |
10001 | 快中断 |
10010 | 中断 |
10011 | 管理 |
10111 | 中止 |
11011 | 未定义 |
11111 | 系统 |
20.状态寄存器访问指令MRS,MSR
- MRS: 状态寄存器到通用寄存器的传送指令(读状态寄存器)
- MSR: 通用寄存器到状态寄存器的传送指令(写状态寄存器)
- MRS和MSR指令可以实现对状态寄存器的读、修改、写操作,即修改状态寄存器的值。
21.异常处理器模式
异常类型 | 模式 | 向量地址 |
---|---|---|
复位 | 管理 | 0x00000000 |
未定义指令 | 未定义 | 0x00000004 |
软件中断(SWI) | 管理 | 0x00000008 |
预取中止(取指令存储器中止) | 中止 | 0x0000000C |
数据中止(数据访问存储器中止) | 中止 | 0x00000010 |
IRQ(中断) | IRQ | 0x00000018 |
FIQ(快速中断) | FIQ | 0x0000001C |
22.异常优先级
异常类型 | 优先级 |
---|---|
复位 | 1(最高优先级) |
数据中止 | 2 |
FIQ | 3 |
IRQ | 4 |
预取中止 | 5 |
未定义指令 | 6 |
SWI | 6(最低优先级) |
23.异常注意
- 中断返回指令的寄存器列表(其中必须包括PC)后的“^”符号表示这是一条特殊形式的指令。这条指令在从存储器中装载PC的同时(PC是最后恢复的),CPSR也得到恢复。
- 使用的堆栈指针SP(R13)是属于异常模式的寄存器,每个异常模式有自己的堆栈指针。如R13_irq
- 堆栈指针应必须在系统启动时初始化。
24.进入异常
-
1.在适当的LR中保存下一条指令的地址(R14_irq),当异常入口来自:
- ARM状态,那么ARM7TDMI将当前指令地址加4或加8复制(取决于异常的类型)到LR中;
- 为Thumb状态,那么ARM7TDMI将当前指令地址加4或加8 (取决于异常的类型)复制到LR中。
-
2.将CPSR复制到适当的SPSR(如SPSR_irq)中;
-
3.将CPSR模式位强制设置为与异常类型相对应的值;
-
4.强制PC从相关的异常向量处取指。
25.异常处理
- ARM7TDMI内核在中断异常时置位中断禁止标志(CPSR 第I位赋值=0x1),这样可以防止不受控制的异常嵌套
- 异常总是在ARM状态中进行处理。当处理器处于Thumb状态时发生了异常,在异常向量地址装入PC时,会自动切换到ARM状态。
- 除了复位异常外,其余的异常都需要返回。
- 当异常结束时,异常处理程序必须:
- 1.将LR(如R14_irq)中的值减去偏移量后存入PC,偏移量根据异常的类型而有所不同;
- 2.将SPSR(如SPSR_irq)的值复制回CPSR;
- 3.若在进入异常处理时设置了中断禁止标志(I/F位)则清零该标志。
- 无论发生什么异常(除复位),内核总是会首先将 PC-4 放到LR寄存器中。
25.软件中断指令(SWI)
- 使用软件中断(SWI)指令可以进入管理模式,通常用于请求一个特定的管理函数。
- SWI处理程序通过执行下面的指令返回:
MOVS PC,R14_svc
这个动作恢复了PC和CPSR并返回到SWI之后的指令。 - PC未更新
26.未定义的指令(UND)
- 当ARM7TDMI处理器遇到一条自己和系统内任何协处理器都无法处理的指令时,ARM7TDMI内核执行未定义指令异常程序。
- 软件可使用这一机制通过模拟未定义的协处理器指令来扩展ARM指令集。
- 在模拟处理了失败的指令后,陷阱程序执行下面的指令:
MOVS PC,R14_und
这个动作恢复了PC和CPSR并返回到未定义指令之后的指令。 - PC未更新
27.快速中断请求(FIQ)
- 快速中断请求(FIQ)适用于对一个突发事件的快速响应,这得益于在ARM状态中,快中断模式有8个专用的寄存器可用来满足寄存器保护的需要(这可以加速上下文切换的速度)。
- 不管异常入口是来自ARM状态还是Thumb状态,FIQ处理程序都会通过执行下面的指令从中断返回:
SUBS PC,R14_fiq,#4
- 在一个特权模式中,可以通过置位CPSR中的F位来禁止FIQ异常。
- PC已更新
28.中断请求(IRQ)
- 中断请求(IRQ)异常是一个由nIRQ输入端的低电平所产生的正常中断(在具体的芯片中,nIRQ由片内外设拉低,nIRQ是内核的一个信号,对用户不可见)。
- IRQ的优先级低于FIQ。进入FIQ处理时FIQ和IRQ都被禁。在一个特权模式下,可通过置位CPSR中的I 位来禁止IRQ。
- 不管异常入口是来自ARM状态还是Thumb状态,FIQ处理程序都会通过执行下面的指令从中断返回:
SUBS PC,R14_irq,#4
- PC已更新
29.FIQ为什么比IRQ快呢?
- FIQ比IRQ有更高优先级,如果FIQ和IRQ同时产生,那么FIQ先处理
- ARM的FIQ模式提供了更多的banked寄存器,R8,R9,R10,R11,R12,模式切换时CPU自动保存这些值到banked寄存器,退出FIQ模式时自动恢复
- FIQ的中断向量地址在0x0000001C,而IRQ的在0x00000018。这样可以直接在1C处放FIQ的中断处理程序,不需要跳转,所以响应速度快。
- IRQ和FIQ的中断响应延迟有区别,IRQ的响应并不及时,从Verilog仿真来看,IRQ会延迟几个指令周期才跳转到中断向量处
30.中止(ABT)
- 中止发生在对存储器的访问不能完成时,当出现异常后,要重新再执行一次这条指令,中止包含两种类型:
- 预取中止: 发生在指令预取过程中
- 数据中止: 发生在对数据访问时
31.预取中止
- 当发生预取中止时,ARM7TDMI内核将预取的指令标记为无效,但在指令到达流水线的执行阶段时才进入异常。
- 如果指令在流水线中因为发生分支而没有被执行,中止将不会发生。
- 在处理中止的原因之后,不管处于哪种处理器操作状态,处理程序都会执行下面的指令恢复PC和CPSR并重试被中止的指令:
SUBS PC,R14_abt,#4
- PC未更新
32.数据中止
- 在修复产生中止的原因后,不管处于哪种处理器操作状态,处理程序都必须执行下面的返回指令,这个动作恢复了PC和CPSR并重试被中止的指令:
SUBS PC,R14_abt,#8
- PC已更新
三、ARM指令集
1.ARM指令概述
- ARM微处理器是基于精简指令计算机==(RISC)==的原理设计的,指令集和相关译码机制比较简单。
- ARM7系列微处理器具有32位的ARM指令集和16位的Thumb指令集
- ARM指令集效率高,但是代码密度低,占用较大的内存空间;
- Thumb指令集属于ARM指令集的子集,具有较好的代码密度,功能简单。
- 所有的ARM指令都是有条件执行
- 而Thumb指令集只有一条指令(B)具有条件执行的功能。
- ARM指令和Thumb指令可以相互调用,两者之间的状态切换所用的开销几乎为0。
2.ARM处理器寻址方式
ARM处理器具有9种基本寻址方式。
- (1) 寄存器寻址
- (2) 立即寻址
- (3) 寄存器移位寻址
- (4) 寄存器间接寻址
- (5)== 基址寻址==
- (6) 多寄存器寻址
- (7) 堆栈寻址
- (8) 块拷贝寻址
- (9) 相对寻址
3.寄存器寻址
- 操作数的值在寄存器中,指令中的地址码字段指出的是寄存器编号,指令执行时直接取出寄存器值来操作。
- 寄存器寻址指令举例如下:
- MOV R1,R2 ;将R2的值存入R1
- SUB R0,R1,R2 ;将R1的值减去R2的值,结果保存到R0
4.立即寻址
- 立即寻址指令中的操作码字段后面的地址码部分即是操作数本身,也就是说,数据就包含在指令当中,取出指令也就取出了可以立即使用的操作数(这样的数称为立即数)。
- 立即寻址指令举例如下:
- SUBS R0,R0,#1 ;R0减1,结果放入R0,并且影响标志位
- MOV R0,#0xFF000 ;将立即数0xFF000装入R0寄存器
5.寄存器移位寻址
- 寄存器移位寻址是ARM指令集特有的寻址方式。当第2个操作数是寄存器移位方式时,第2个寄存器操作数在与第1个操作数结合之前,选择进行移位操作。
- 寄存器移位寻址指令举例如下:
- MOV R0,R2,LSL #3 ;R2的值左移3位,结果放入R0,即是R0=R2×8
- ANDS R1,R1,R2,LSL R3 ;R2的值左移R3位,然后和R1相 “与”操作,结果放入R1
6.寄存器间接寻址
- 寄存器间接寻址指令中的地址码给出的是一个通用寄存器的编号,所需的操作数保存在寄存器指定地址的存储单元中,即寄存器为操作数的地址指针。
- 寄存器间接寻址指令举例如下:
- LDR R1,[R2] ;将R2指向的存储单元的数据读出保存在R1中
- STR R1,[R0]
7.基址寻址
- 基址寻址就是将基址寄存器的内容与指令中给出的偏移量相加,形成操作数的有效地址。
- 基址寻址指令举例如下:
- LDR R2,[R3,#0x0C] ;读取R3+0x0C地址上的存储单元的内容,放入R2
- STR R1,[R0,#-4]! ;先R0-4,然后把R1的值保存到R0-4指定的存储单元
8.多寄存器寻址
- 多寄存器寻址一次可传送几个寄存器值,允许一条指令传送16个寄存器的任何子集或所有寄存器。
- 多寄存器寻址指令举例如下:
- LDMIA R1!,{R2-R7,R12} ;将R1指向的单元中的数据读出到R2~R7、R12中(R1自动加4)
- STMIA R0!,{R2-R7,R12} ;将寄存器R2~R7、R12的值保存到R0指向的存储; 单元中(R0自动加4)
- 使用多寄存器寻址指令时,寄存器子集的顺序是按由小到大的顺序排列,连续的寄存器可用“-”连接;否则用“,”分隔书写。
9.堆栈寻址
- 堆栈是一个按特定顺序进行存取的存储区,操作顺序为==“后进先出”== 。
- 堆栈寻址是隐含的,它使用一个专门的寄存器(堆栈指针)指向一块存储区域(堆栈),指针所指向的存储单元即是堆栈的栈顶。
- 存储器堆栈可分为两种:
- 向上生长:向高地址方向生长,称为递增堆栈
- 向下生长:向低地址方向生长,称为递减堆栈
10.块拷贝寻址
- 块拷贝寻址方式使用多寄存器传送指令将数据块从存储器的某一位置拷贝到另一位置。
- 如:
- STMIA R0!,{R1-R7} ;将R1~R7的数据保存到存储器中。存储指针在保存第一个值之后增加,增长方向为向上增长。
- STMIB R0!,{R1-R7} ;将R1~R7的数据保存到存储器中。存储指针在保存第一个值之前增加,增长方向为向上增长。
- 常用的加载存储指令有:
- LDM—批量数据加载指令;
- STM—批量数据存储指令。
- LDM(或STM)指令的格式为:LDM(或STM){条件}{类型} 基址寄存器{!},寄存器列表
- {类型}为以下几种情况:
- IA 每次传送后地址加4;
- IB 每次传送前地址加4;
- DA 每次传送后地址减4;
- DB 每次传送前地址减4;
- FD 满递减堆栈;
- ED 空递减堆栈;
- FA 满递增堆栈;
- EA 空递增堆栈;
- {!}为可选后缀,若选用该后缀,则当数据传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变
11.相对寻址
- 相对寻址是基址寻址的一种变通。由程序计数器PC提供基准地址,指令中的地址码字段作为偏移量,两者相加后得到的地址即为操作数的有效地址
- MOV PC,R14 ;返回
12.指令格式
<opcode> {<cond>} {S} <Rd> ,<Rn>{,<operand2>}
- 其中<>号内的项是必须的,{ }号内的项是可选的。各项的说明如下:
- opcode:指令助记符;
- cond:执行条件;
- S:是否影响CPSR寄存器的值;
- Rd:目标寄存器;
- Rn:第1个操作数的寄存器;
- operand2:第2个操作数;
- operand2有如下的形式:
- #immed_8r ——常数表达式;
- Rm ——寄存器方式;
- Rm, shift ——寄存器移位方式;
13.ARM存储器访问指令
- ARM处理器是典型的RISC处理器,对存储器的访问只能使用加载和存储指令实现。
- 冯•诺依曼存储结构,程序空间、RAM空间及I/O映射空间统一编址,除对RAM操作以外,对外围IO、程序数据的访问均要通过加载/存储指令进行。
- 存储器访问指令分为单寄存器操作指令和多寄存器操作指令。
14.LDR和STR
- LDR/STR指令寻址非常灵活,它由两部分组成,其中一部分为一个基址寄存器,可以为任一个通用寄存器;另一部分为一个地址偏移量。地址偏移量有以下3种格式:
- 立即数:立即数可以是一个无符号的数值。这个数据可以加到基址寄存器,也可以从基址寄存器中减去这个数值。
- 寄存器:寄存器中的数值可以加到基址寄存器,也可以从基址寄存器中减去这个数值。
- 寄存器及移位常数:寄存器移位后的值可以加到基址寄存器,也可以从基址寄存器中减去这个数值。
- 从寻址方式的地址计算方法分,加载/存储指令有以下3种格式:
- 零偏移: 如:LDR Rd,[Rn]
- 前索引偏移(前变址):如:LDR Rd,[Rn,#0x04]!
- 后索引偏移(后变址):如:LDR Rd,[Rn],#0x04
- 有符号位半字/字节加载是指用符号位加载扩展到32位,无符号半字加载是指用零扩展到32位;
- 地址对齐——半字读写的指定地址必须为偶数,否则将产生不可靠的结果。
- LDM和STM的主要用途是现场保护、数据复制、常数传递等
- 后缀“!”表示最后的地址写回到Rn中。
15.多寄存器存取
-
模式 说明 模式 说明 IA 每次传送后地址加4 FD 满递减堆栈 IB 每次传送前地址加4 ED 空递减堆栈 DA 每次传送后地址减4 FA 满递增堆栈 DB 每次传送前地址减4 EA 空递增堆栈 数据块传送操作 堆栈操作 - 进行堆栈操作操作时,要先设置堆栈指针(SP),然后使用堆栈寻址指令STMFD/LDMFD 、STMED/LDMED、STMFA/LDMFA和STMEA/LDMEA实现堆栈操作。
- 后缀“^”不允许在用户模式或系统模式下使用。
- 若在LDM指令且寄存器列表中包含有PC时使用,那么除了正常的多寄存器传送外,将SPSR也拷贝到CPSR中,这可用于异常处理返回。
- 使用后缀“^”进行数据传送且寄存器列表不包含PC时,加载/存储的是用户模式的寄存器,而不是当前异常模式的寄存器。
16.寄存器和存储器交换指令
- SWP指令用于将一个内存单元(该单元地址放在寄存器Rn中)的内容读取到一个寄存器Rd中,同时将另一个寄存器Rm的内容写入到该内存单元中。
- 指令格式如下:
SWP{cond}{B} Rd,Rm,[Rn]
- B为可选后缀,若有B,则交换字节,否则交换32位字;Rd用于保存从存储器中读入的数据;Rm的数据用于存储到存储器中,若Rm与Rd相同,则为寄存器与存储器内容进行交换;Rn为要进行数据交换的存储器地址,Rn不能与Rd和Rm相同。
- SWP R1,R1,[R0] ;将R1的内容与R0指向的存储单元的内容进行交换
- SWPB R1,R2,[R0] ;将R0指向的存储单元内的容读取一字节数据到R1中==(高24位清零),并将R2的内容写入到该内存单元中(最低字节有效)== ,只写R2的最低8位给内存
17.ARM数据处理指令
- 数据处理指令大致可分为3类: 数据传送指令;算术逻辑运算指令;比较指令。
- 数据处理指令只能对寄存器的内容进行操作,而不能对内存中的数据进行操作。
- 所有ARM数据处理指令均可选择使用S后缀,并影响状态标志。
- 比较指令CMP、CMN、TST和TEQ不需要后缀S,它们会直接影响状态标志。
- MOV指令将立即数或寄存器传送到目标寄存器(Rd),可用于移位运算等操作。
- MVN指令将立即数或寄存器(operand2)按位取反后传送到目标寄存器(Rd),因为其具有取反功能,所以可以装载范围更广的立即数。
- 算术运算
助记符 说明 操作 条件码位置 ADD Rd, Rn, operand2 加法运算指令 Rd←Rn+operand2 ADD{cond}{S} SUB Rd, Rn, operand2 减法运算指令 Rd←Rn-operand2 SUB{cond}{S} RSB Rd, Rn, operand2 逆向减法指令 Rd←operand2-Rn RSB{cond}{S} ADC Rd, Rn, operand2 带进位加法 Rd←Rn+operand2+Carry ADC{cond}{S} SBC Rd, Rn, operand2 带进位减法指令 Rd←Rn-operand2-(NOT)Carry SBC{cond}{S} RSC Rd, Rn, operand2 带进位逆向减法指令 Rd←operand2-Rn-(NOT)Carry RSC{cond}{S} - 逻辑运算指令
助记符 说明 操作 条件码位置 AND Rd, Rn, operand2 逻辑与操作指令 Rd←Rn & operand2 AND{cond}{S} ORR Rd, Rn, operand2 逻辑或操作指令 Rd←Rn | operand2 ORR{cond}{S} EOR Rd, Rn, operand2 逻辑异或操作指令 Rd←Rn ^ operand2 EOR{cond}{S} BIC Rd, Rn, operand2 位清除指令 Rd←Rn & (~operand2) BIC{cond}{S} - 比较指令
助记符 说明 操作 条件码位置 CMP Rn, operand2 比较指令 标志N、Z、C、V ←Rn-operand2 CMP{cond} CMN Rn, operand2 负数比较指令 标志N、Z、C、V←Rn+operand2 CMN{cond} TST Rn, operand2 位测试指令 标志N、Z、C、V←Rn & operand2 TST{cond} TEQ Rn, operand2 相等测试指令 标志N、Z、C、V←Rn ^ operand2 TEQ{cond} - 乘法指令
助记符 | 说明 | 操作 | 条件码位置 |
---|---|---|---|
MUL Rd,Rm,Rs | 32位乘法指令 | Rd←Rm*Rs (Rd≠Rm) | MUL{cond}{S} |
MLA Rd,Rm,Rs,Rn | 32位乘加指令 | Rd←Rm*Rs+Rn (Rd≠Rm) | MLA{cond}{S} |
UMULL RdLo,RdHi,Rm,Rs | 64位无符号乘法指令 | (RdHi,RdLo) ←Rm*Rs | UMULL{cond}{S} |
UMLAL RdLo,RdHi,Rm,Rs | 64位无符号乘加指令 | (RdHi,RdLo) ←Rm*Rs+(RdHi,RdLo) | UMLAL{cond}{S} |
SMULL RdLo,RdHi,Rm,Rs | 64位有符号乘法指令 | (RdHi,RdLo) ←Rm*Rs | SMULL{cond}{S} |
SMLAL RdLo,RdHi,Rm,Rs | 64位有符号乘加指令 | (RdHi,RdLo) ←Rm*Rs+(RdHi,RdLo) | SMLAL{cond}{S} |
- 分支指令
- B指令,该指令跳转范围限制在当前指令的±32M字节地址内(ARM指令为字对齐,最低2位地址固定为0)。
- BL指令适用于子程序调用,使用该指令后,下一条指令的地址被拷贝到R14(即LR) 中,然后跳转到指定地址运行程序。跳转范围限制在当前指令的±32M字节地址内。
- BX指令,该指令可以根据跳转地址(Rm)的最低位来切换处理器状态,bit[0]=0为ARM状态,否则为Thumb状态。其跳转范围限制在当前指令的±32M字节地址内(ARM指令为字对齐,最低2位地址固定为0)。
| 助记符 | 说明 | 操作 | 条件码位置 |
| -------------- | ------------------------ | ---------------------------- | ------------ |
| B label | 分支指令 | PC←label | B{cond} |
| BL label | 带链接的分支指令 | LR←PC-4,PC←label | BL{cond} |
| BX Rm | 带状态切换的分支指令 | PC←label,切换处理器状态 | BX{cond} |
- 只有MRS指令可以对状态寄存器CPSR和SPSR进行读操作。
- 只有MSR指令可以对状态寄存器CPSR和SPSR进行写操作
- 只有在特权模式下才能修改状态寄存器。
- 程序中不能通过MSR指令直接修改CPSR中的T控制位来实现ARM状态/Thumb状态的切换,必须使用BX指令完成处理器状态的切换(因为BX指令属分支指令,它会打断流水线状态,实现处理器状态切换)。
18.ARM伪指令
- ARM伪指令有四条,分别为ADR伪指令、ADRL伪指令、LDR伪指令、NOP伪指令。
- ADR伪指令,小范围的地址读取
- ADRL伪指令,中等范围的地址读取
- LDR伪指令,大范围的地址读取
- NOP伪指令, 空操作伪指令
19.Thumb指令集
- 在编写Thumb指令时,先要使用伪指令CODEl6声明,而且在ARM指令中要使用BX指令跳转到Thumb指令,以切换处理器状态。
- 编写ARM指令时,则可使用伪指令CODE32声明。
- 除了分支指令B有条件执行功能外,其它指令均为无条件执行。
20.Thumb指令集与ARM指令集的区别
- 分支指令 程序相对转移,特别是条件跳转与ARM代码下的跳转相比,在范围上有更多的限制。
- 数据处理指令
- 数据处理操作比ARM状态的更少。
- 访问寄存器R8~R15受到一定限制。
- 除MOV和ADD指令访问R8~ R15外,其它数据处理指令总是更新CPSR中的ALU状态标志。
- 访问寄存器R8~R15的Thumb数据处理指令不能更新CPSR中的ALU状态标志。
- 单寄存器加载和存储指令 在Thumb状态下,单寄存器加载和存储指令只能访问寄存器R0~R7。
- 多寄存器加载和存储指令
- LDM和STM指令可以将任何范围为R0~R7的寄存器子集加载或存储,多寄存器加载和存储指令只有LDMIA和STMIA指令。
- PUSH和POP指令使用堆栈指令R13作为基址实现满递减堆栈。
- 除R0~R7外,PUSH指令还可以存储LR, 并且POP指令可以加载PC。
四、汇编程序设计
1.ARM伪操作
- 在ARM的汇编程序中,有如下几种伪指令:符号定义伪指令、数据定义伪指令、汇编控制伪指令、宏指令以及其他伪指令。
2.符号定义伪指令
- GBLA伪指令用于定义一个全局的数字变量,并初始化为0;
- GBLL伪指令用于定义一个全局的逻辑变量,并初始化为F(假);
- GBLS伪指令用于定义一个全局的字符串变量,并初始化为空;
- 以上三条伪指令用于定义全局变量,因此在整个程序范围内变量名必须唯一。
- LCLA伪指令用于定义一个局部的数字变量,并初始化为0;
- LCLL伪指令用于定义一个局部的逻辑变量,并初始化为F(假);
- LCLS伪指令用于定义一个局部的字符串变量,并初始化为空;
- 以上三条伪指令用于声明局部变量,在其作用范围内变量名必须唯一。
- SETA伪指令用于给一个数学变量赋值;
- SETL伪指令用于给一个逻辑变量赋值;
- SETS伪指令用于给一个字符串变量赋值;
- 其中,变量名为已经定义过的全局变量或局部变量,表达式为将要赋给变量的值。
- RLIST伪指令可用于对一个通用寄存器列表定义名称,使用该伪指令定义的名称可在ARM指令LDM/STM中使用。
3.数据定义(Data Definition)伪操作
- DCB 用于分配一片连续的字节存储单元并用指定的数据初始化。
- DCW(DCWU)用于分配一片连续的半字存储单元并用指定的数据初始化。
- DCD(DCDU) 用于分配一片连续的字存储单元并用指定的数据初始化。
- DCFD(DCFDU)用于为双精度的浮点数分配一片连续的字存储单元并用指定的数据初始化。
- DCFS(DCFSU) 用于为单精度的浮点数分配一片连续的字存储单元并用指定的数据初始化。
- DCQ(DCQU) 用于分配一片以8字节为单位的连续的存储单元并用指定的数据初始化。
- DCDO 用于分配一段字的内存单元,将每个单元的内容初始化为该单元相对于基址寄存器的偏移量
- DCI 用于分配一段字的内存单元,并用单精度的浮点数据初始化,指定内存单元存放的是代码,而不是数据
- SPACE 用于分配一片连续的字节存储单元,并初始化为0
- MAP 用于定义一个结构化的内存表首地址
- FIELD 用于定义一个结构化的内存表的数据域
- LTORG 用于声明一个文字池(缓冲池)
4.汇编控制
- IF、ELSE、ENDIF条件汇编代码文件内的一段源代码
- WHILE、WEND根据条件重复汇编
- MACRO、MEND标识宏定义的开始和结束
- MEXIT中途跳转出宏
- AREA伪操作用于定义一个代码段或数据段
- ALIGN伪操作可通过添加填充字节的方式,使当前位置满足一定的对齐方式。
- ENTRY伪操作用于指定程序的入口点。在一个完整的汇编语言程序中至少要有一个ENTRY
- END伪操作用于通知汇编器已经到了源程序的结尾。
- EQU伪操作用于为程序中的常量、标号等定义一个等效的字符名称,类似于C语言中的#define。其中EQU可用“*”代替。
- EXPORT伪操作用于在程序中声明一个全局的标号,该标号可在其他的文件中引用。EXPORT可用GLOBAL代替。标号在程序中区分大小写。
- IMPORT伪操作用于通知编译器要使用的标号在其他的源文件中定义,但要在当前源文件中引用,
- GET伪操作用于将一个源文件包含到当前的源文件中,并将被包含的源文件在当前位置进行汇编处理。
- EXTERN伪操作用于通知编译器要使用的标号在其他的源文件中定义,但要在当前源文件中引用,如果当前源文件实际并未引用该标号,该标号就不会被加入到当前源文件的符号表中。
- INCBIN伪操作用于将一个二进制目标代码文件或任意格式的数据文件包含到当前的源文件中,
- RN 伪指令用于给一个寄存器定义一个别名。采用这种方式可以方便程序员记忆该寄存器的功能。其中,名称为给寄存器定义的别名,表达式为寄存器的编码。
5.数据比较跳转
- CMP R5,#10 ;做减法
- BEQ BRANCH1 ;如果R5为10,则跳转到BRANCH1
- CMP R1,R2
- ADDHI R1,R1,#1 ;如果R1>R2,则R1=R1+1
- ADDLS R1,R1,#2 ;如果R1<=R2,则R1=R1+2……
- ANDS R1,R1,#0x80 ;R1=R1&0x80,并设置相应的标志位
- BNE WAIT ;如果R1的第7位0,则跳转到WAIT