文章目录
- 1 嵌入式系统概述
- 2 ARM11体系结构
- 3 ARM为处理器的指令系统
- 4 S3C6401处理器
- 5 GPIO接口
- 8 ADC和触摸屏接口
- 9 Andrioid系统开发概述
- 10 Android系统开发环境
- 11 Boot Loader
1 嵌入式系统概述
1.1 嵌入式系统基本概念
1.1.1 嵌入式系统定义
IEEE(国际电气和电子工程师协会)的定义:嵌入式系统是用于控制监视或者辅助操作机器和设备的装置。
1.1.2 嵌入式系统的发展
直到19世纪70年代末,随着微电子技术的发展,嵌入式计算机才逐步兴起。
1. 嵌入式应用始于微型机时代
电子数字计算机诞生于1946年,在初期的计算机都是在机房中的。直到19世纪70年代微处理器的出现,才使计算机发生了历史性的变化。
随着微处理器的发展,具有高速数据计算能力的微型机表现出的计算能力引起了控制专业人士的关注。他们将微型计算机通过电气或者是机械加固,然后配置各种外围的电路之后安装到大型船舶的自动驾驶或者是轮船监测系统中。
并且为了区分于原有的通用计算机系统,我们把嵌入到对象体系中的控制计算机称之为嵌入式计算机系统。其本质就是将一个计算机嵌入到一个对象体系中。
2. 现代计算机技术的两大分支
现代计算机技术有两个分支,就是通用计算机和嵌入式计算机。
通用计算机系统的技术要求高速海量的数据计算,技术发展方向是总线速度的无限提升、存储容量的无限扩大。
嵌入式计算机系统的控制技术要求是对对象的智能化控制能力,技术发展方向是与对象体系密切相关的嵌入式性能控制能力与控制的可靠性。
3. 嵌入式发展的里程碑
纵观嵌入式技术的发展历程,大致经历了4个阶段。
- 以单芯片为核心的可编程控制器形式的系统具有监测、伺服、指示设备相配合的功能。这类系统大部分应用一些专业性较强的工控领域。一般没有操作系统的支持,通过汇编语言对系统直接进行控制,运行结束后再清除内存。
- 以嵌入式cpu为基础,以简单操作系统为核心的嵌入式系统。在1980年左右,随着微电子工艺水平的提高,集成电路制造商开始把嵌入式应用中所需要的微处理器io接口串行接口以及ram和rom等部件通通集成到一片超大规模集成电路中制造出面向io设计的微控制器。在这一时期出现了大量高可靠低功耗的嵌入式cpu,但通用性比较弱。
- 以嵌入式操作系统为标志的嵌入式系统,20世纪90年代嵌入式系统飞速发展面向实时信号处理算法的dsp产品,则向着高速、高精度、低功耗的方向发展。随着硬件实时性的需求提高,嵌入式系统的软件规模不断扩大,逐渐形成了实时多任务操作系统rtos,并开始成为嵌入式系统的主流。
- 以internet为标志的嵌入式系统。目前大多数的嵌入式系统还孤立于internet之外信息。时代和数字时代的到来为嵌入。式系统的发展带来巨大机遇。
1.1.3 嵌入式系统的特点
- 面向特定应用
- 功耗低、体积小、集成度高、成本低
- 具有较长的生命周期
- 具有固化的代码
- 需要专用开发工具和环境
- 需要RTOS开发平台
- 以应用专家为主
1.2 嵌入式系统分类
1.2.1 单个微处理器
由单片的嵌入式处理器组成,集成了io设备以及ad转换设备,再加上简单的电源和时钟就可以工作,常用于小型设备中。
1.2.2 嵌入式处理器可扩展的系统
根据需要,可以扩展存储器,同时也可以使用片上的存储器,处理器一般容量在64k左右,字长为8位或者是16位在处理器上扩展少许的存储器和外接接口。
1.2.3 复杂的嵌入式系统
一般是16、32位,用于大规模应用。由于软件量大,所以需要扩展存储器。破产存储器一般都在一1M以上,外部接口一般仍然集成在处理器上。常用的嵌入式处理器有ARM系列,摩托罗拉的powerPC系列、Coldfire系列。
在开关装置、控制器、电梯等方面可以看到这类嵌入式系统的应用。
1.2.4 在制造或过程控制中使用的计算机系统
计算机与仪器、机械及设备与系统相连来控制这些装置。这类系统包括自动仓储系统和发货系统,在这些系统中计算机用于总体控制和监视,而不是对单个设备直接控制。
1.3 嵌入式处理器
全世界处理器的品种已经超过了1000多种,流行的体系有30多个系列。
嵌入式处理器的寻址空间一般是64k~16m。当然了,现在的STM32F407已经到了4G,这本书有点老了,处理速度0.1-2000MIPS,常用封装8-144个引脚。
根据现状,嵌入式处理器可以分成嵌入式微控制器EMCU、嵌入式微处理器EMPU、嵌入式dsp处理器EDSP、嵌入式片上系统ESoC。
1.4 嵌入式系统的组成
嵌入式系统一般都是由硬件、软件以及开发工具和开发系统三部分组成。
1.4.1 嵌入式系统的硬件
1.4.2 嵌入式系统的软件
- 驱动层程序
- 实时操作系统
- 操作系统的应用程序接口,应用程序接口是一系列复杂的函数、消息和机构的集合体。嵌入式操作系统下的api和一般操作系统下的api在功能含义和知识体系上完全一致。
- 应用程序。实际的嵌入式系统应用软件建立在系统的主任务基础。之上,用户应用程序主要通过调用系统的api函数对系统进行操作,完成用户功能的开发。
1.5 嵌入式操作系统
嵌入式操作系统是一种专用的可定制的操作系统。除了能完成一般操作系统的功能,如进程管理、存储管理、文件管理、设备管理等,还可以包括和硬件相关的底层驱动软件,系统内核设备驱动接口,通信协议图形界面标准化浏览器等。
1.5.1 嵌入式操作系统的发展
在最开始的控制领域,中设计者往往根据汇编语言或高级语言编程对系统进行直接控制,没有操作系统的概念。
随着嵌入式cpu的投入使用嵌入式操作系统也随之发展起来。
1.5.2 嵌入式操作系统的分类
收费不收费
- 免费的操作系统有:Linux、Embedded Linux、FreeRTOS等。
- 收费的嵌入式操作系统:VxWorks、Windows CE等。
按照系统对时间的敏感程度:
- 硬实时系统:系统对响应时间有严格的要求。 响应时间不满足的是不能接受的,会导致系统的崩溃和致命错误。
- 软实时系统:系统对响应时间没有严格要求。响应时间如果不能满足要求,可能会导致结果错误,但不影响系统的正常运行。
- 非实时系统:系统的响应时间没有要求,如果响应时间不满足要求,也不会影响系统运行。
1.5.4 主流嵌入式操作系统简介
1. VxWorks
VxWorks操作系统是WindRiver公司于1983年设计的一种嵌入式实时操作系统RTOS,是嵌入式开发环境的关键组成部分。
支持多种处理器x86、i960、Sun Sparc、Motorola MC68xxx、MIPS RX0000、POWER PC等。
这个系统比较贵,通常要花费数10万才能建起一个可靠的开发环境。
2. Windows CE
Windows CE是微软开发的32位嵌入式操作系统,得益于windows优秀的图形用户界面,与桌面版的windows基本一致。
3. μC/OS-II
μC/OS-II是一种开源但不免费的RTOS,具有可剥夺实时内核。μC/OS-II是μC/OS的升级版,发布1992年。目前,μC/OS-II已经被移值到40多种不同架构的CPU上,可以运行在8位到64位的各种操作系统之上。
4. 嵌入式Linux
Linux最早由芬兰人Linus Torvalds于1991年创立,经过短短十几年发展,已经成为一个功能强大稳定可靠的操作系统。典型的Linux系统有Red Hat、Ubuntu、Red Flag等。
我们要讲的嵌入式Linux是标准Linux在嵌入式系统上的移植。
2 ARM11体系结构
2.1 ARM微处理器概述
2.1.1 arm公司简介
ARM于1990年11月在英国伦敦成立前身为 Acorn计算机公司后改名为advance RISC Machines Limited公司(ARM)。
采用arm技术知识产品核的微处理器就是我们通常所说的ARM微处理器。基于arm技术的微处理器应用约占了30位RISC微处理器75%以上的市场份额。
2.1.2 ARM特点
- 体积小、功耗低、成本低、性能高
- 支持Thumb(16位)/ARM(32位)双指令集,很好的兼容8位\16位器件。
- 大量使用寄存器,指令执行速度高。
2.1.3 ARM体系结构的版本
到目前ARM体系一共定义了7个版本的指令集,以版本V1-V7表示。
版本V6
2001年发布。
使用此版本的核: ARM11、ARM1156T2-S、ARM1176JZF-S、ARM11JZF-S。
版本V7
ARM体系V7是在2005年发布。该版本扩展了130条指令的Thumb2指令集。具有NEON媒体引擎,该引擎具有SIMD执行流水线和寄存器堆可共享访问的l1、l2高速缓存。
使用次版本的处理器核:ARM Cortex。
2.2 ARM11 系列微处理器
ARM11系列微处理器是新一代的RISC处理器,但它是基于 arm v6的第1代设计实现的,系列主要有ARM1136J、ARM1156T2。
ARM11系列处理器在其性能上有巨大提升,首先推出的350M - 500M 的时钟频率的内核,在未来将上升到1GHz。
通过动态调整时钟频率和供应电压,开发者完全可以控制性能和功耗间作出平衡。在0.13微米的工艺下,1.2V条件下,ARM11处理器的功耗可以低至0.4mW/MHz。
ARMv6架构决定了可以达到高性能处理器的基础。
ARM11处理器规格如上所示。
2.3 ARM11系列微处理器架构
Arm11系列包括了arm11MPCore处理器ARM1176处理器、ARM1156处理器和ARM1136处理器。
2.4 ARM11 流水线
流水线是RISC执行指令时采用的一种重要机制。流水线既可以达到更高的性能,还可以让用户更加方便地实现流程。
2.4.1 流水线结构的性能
系统在处理数据时,一个指令周期含有4~6个时钟脉冲。每个脉冲周期由不同的部件完成不同的操作。
流水线结构是指每个时钟脉冲都接收下一条处理数据。的指令,只是不同部件。做不同的事情,流水线处理器。一般把一条指令的执行分成几个级,每一级在一个时钟周期内完成。
如果说处理器的流水线有k级,那么同时可执行的指令条数就是k。每一条指令处于不同的执行阶段。
2.4.2 流水线级数的影响
ARM7采用的是三级流水线,arm9采用的是5级流水线,ARM10采用的是6级流水线,ARM11处理器采用的是8级流水线,比以前的ARM内核减少了40%的吞吐量,8级流水线可以同时执行8条指令。
当出现多周期指令时跳转分支指令和中断发生时,流水线都会发生阻塞,而且相邻指令之间也可能因为寄存器冲突导致流水阻塞,从而降低了流水线效率。
同时随着系统的时钟频率的增加,指令执行周期也相应减少对其对硬件要求也更高,而且以内核执行一条指令前需要更多的周期来填充流水线。
Arm流水线的一条指令只有在完全通过执行阶段才会被处理。如果随后的指令需要用到前面指令的执行结果作为输入,它就要等前面的指令执行完。
2.4.3 ARM11处理器中流水线的管理
为了解决延时避免流水线的数据,冲突让前面的指令执行的结果能够快速进入到后面指令的流水线中。Rm11处理器采用了预测技术、存储管理、并行机制等技术来保证最佳的流水线效率。
1 预测技术
对跳转的预测分为两种,静态和动态的预测。
动态预测:在arm处理器中包含了64个4状态跳转地址缓存器,来保存最近使用过的转换地址。通过对这些转换记录地址的查询,处理器就可以预测当前的跳转指令是否会被执行。
静态预测:当采用动态转换预测机制无法在寻址缓冲内找到正确的地址时。ARM11处理器就会从跳转的方式来判断是否执行。静态预测检查分支是向前跳转还是向后跳转。
2. 存储管理
在arm11处理器中,指令和数据可以更长时间地保存在Cache中。
由于物理地质Cache本身的存在,使数据交换避免了反复重载Cache。
3. 流水线的并行机制
在流水线的后端使用了三个并行部件机构。ALU、MAC(乘加)、LS(存取)。
LS流水线是专门用于处理存储操作指令,把数据的存取操作与数据的算术操作的耦合性分隔开来可以更加有效地执行指令。
一旦指令被解码,将根据不同的操作类型发射到不同的执行单元中,考虑到不同的指令需要不同的执行时间。当三类指令先后被发射到流水线中,ALU或者是MAC指令,不会由于LS指令的等待而停下来,他们可以同时被执行,即取址、译码和执行等操作可以重叠执行。
通过技术和机制上的改进,arm11处理器改善了因为级数的增加带来的影响,使系统能在优化到更高的流水线吞吐量的同时,还能保持与以前版本处理器中的流水线同样的有效性。
2.5 ARM工作模式及寄存器组
2.5.1 ARM核工作模式
常规cpu工作核心模块都是由寄存器组和ALU两大模快组成。 Alu完成数据的加工处理,寄存器用来保存数据,这些数据直接参与alu运算。
ARM处理器的寄存器分成许多组,不同的组完成不同环境下的工作,不过他们都共用一套alu数据处理模块。ARM一般有37个寄存器,Cortex A8的ARM核的寄存器则多达40个。
程序状态寄存器是一个32位的寄存器,它指示和记录了当前程序的运行状态。PSR(Program State Register).
2.5.2 ARM寄存器分组
ARM芯片将寄存器分成很多组来运行不同模式下的程序,让cpu运行的更加稳定。
ARM寄存器分为以上8个组,其中User和System两个组的寄存器完全共用,Secure monitor是Cortex A8的ARM核开始追加的模式。
8组寄存器各自拥有可访问的寄存器。
17个寄存器是公用的。另外,多大23个专用的寄存器分散在各个模式组中。
- User模式是程序正常运行的模式,它不需要任何异常的特殊的异常处理。
- Secure monitor模式是安全模式,需要协处理器来启动该模块方能进行工作。
2.5.3 工作模式分析
1. 特权(异常)模式
8组寄存器中,除了User外,其余7种都为特权模式或异常模式。
特权模式有以下规定:
- 对PSR寄存器中的模式位组有修改能力。
- 除了能访问公用寄存器外,还有一些专用寄存器。
除了User模式外,其它的都属于特权模式。
- 异常模式都属于特权模式的类型。
- 异常模式都有自己的专用处理程序入口地址,又称为异常向量表。
2. 中断模式
属于异常模式。ARM核用来接入核外部的异常事件,称为中断。分为FIQ和IRQ两种。
FIQ 快速中断
- 当处理器的快速中断请求引脚有效,而且CPSR寄存器的F控制位被清除时,处理器产生快速中断请求异常中断。
IRQ外部请求中断
- 当处理器的外部中断请求引脚有效。而且CPSR寄存器的I控制位被清除时,处理器产生外部中断请求异常中断。
- 系统中各外设通过该异常中断请求处理中断服务。
2.6 各种模式的工作机制
ARM工作模式的切换分为手动切换与异常切换。
- 在某种特权模式下可以切换到另一个特权模式,但是user不可以。
- 当异常发生时,可以从user模式下切到异常模式下,或切到其它模式下。
2.6.1 CPSR、PC、SPSR_XXX和LR_XX寄存器
当异常发生时LR_XX保存当前PC值,SPSR_XXX保存当前CPSR值。因为此时pc会继续存放异常模式下的指令地址,而CPSR将继续反映异常模式下程序运行状态,所以需要保存。
- 这些动作由硬件自动完成。
异常结束时将CPSR和PC的值恢复,正常程序运行。
- 用户在异常程序的末尾写入一条完成指令PC<=lr,就自动完成CPSR<=SPSR_xxx动作。
2.6.4 Supervisor特权模式
进入Supervisor模式,一般有两种方式,硬件方式芯片复位和软件方式执行swi指令。
2.6.5 Abort特权模式
Abort异常模式由arm11内部硬件自动引发,对内存数据的存储和指令预取失败会引发该异常。
2.6.6 Undefined特权模式
Undefined异常,由arm11内部硬件自动引发,当指令执行一条无法识别的指令时将发生该异常。
2.6.7Secure monitor模式
当有私密的数据程序需要执行时(如货币交易),用户软件调用SMI指令即可进入该模式。
2.6.8 System模式
System特权模式是arm11中的7个特权模式中唯一一个没有自己的程序入口地址的模式,所以它不属于异常模式。
- System模式下的工作寄存器与user用户模式下的寄存器完全一样。
- 但是system模式能操作CPSR_mod权限,也就是说可以切换各种特权模式,访问他们的资源。
2.6.9 ARM中各个异常处理响应优先级
各种异常中断的中断向量地址以及中断的处理优先级如下图。
2.7 进入和退出异常中断的过程
2.7.1 异常中断响应过程
- 保存处理器的当前状态,中断屏蔽位以及各个条件标志位。通过将当前程序状态寄存器CPSR的内容保存到将要执行的异常中断对应的SPSR寄存器中实现。
- 设置当前程序CPSR中相应的位。使处理器进入相应的执行模式。当进入IRQ模式,禁止IRQ中断。当进入FIQ模式,禁止FIQ中断。
- 将寄存器LR-mode(R14)设置成返回地址。R14从R15中得到PC的备份。
- 将程序计数器值pc设置成异常中断的中断向量地址,从而跳转到相应的异常中断处执行。
响应IRQ异常中断处理过程的伪代码:
其它还有响应未定义指令异常中断、响应swi异常中断、响应指令预取中止异常中断、响应数据访问中止异常中断等。
2.7.2 从异常中断处理程序返回
- 恢复被中断的程序的处理器状态。也就是将SPSR-mode的寄存器内容复制到当前程序状态寄存器CPSR中。
- 返回到发生异常中断的指令的下一条指令处执行。也就是将 LR_mode寄存器的内容复制到程序计数器pc中。
3 ARM为处理器的指令系统
3.1 Arm微处理器的指令集概述
3.1.1 Arm微处理器的指令的分类与格式
Arm微处理器的指令集是加载型的,即指令集仅能处理寄存器中的数据,而且处理结果必须要放回寄存器中。
对系统存储器的访问则需要通过专门的加载指令来完成。
ARM微处理器的指令集可以分为跳转指令、数据处理指令、程序状态寄存器处理指令、加载/存储指令,协处理器指令和异常产生指令六大类。
ARM指令集主要包括以下几类:
数据处理指令
- 算术运算指令:
- ADD:将两个操作数相加,并将结果存储在目标寄存器中。例如,
ADD R0, R1, R2
表示将寄存器R1和R2中的值相加,结果存入R0 。 - SUB:执行减法操作。例如,
SUB R3, R4, R5
是用R4中的值减去R5中的值,差存入R3。 - MUL:实现乘法运算。比如
MUL R6, R7, R8
将R7和R8中的值相乘,结果存于R6 。 - ADC:带进位的加法。例如在进行128位加法时,可通过
ADDS R0,R4,R8
;ADCS R1,R5,R9
;ADCS R2,R6,R10
;ADCS R3,R7,R11
实现,其中ADCS
中的S
后缀用于更改进位标志。 - SBC:带进位的减法,可用于有符号数或无符号数的减法运算。
- RSC:带借位的反向减法,用于把操作数2减去操作数1,再减去CPSR中的C条件标志位的反码,并将结果存放到目的寄存器中。
- ADD:将两个操作数相加,并将结果存储在目标寄存器中。例如,
- 逻辑运算指令:
- AND:对两个操作数按位进行与操作。例如,
AND R9, R10, R11
将R10和R11中的每一位进行与运算,结果放入R9,常用于掩码操作。 - ANDS 是 ARM 指令集中的逻辑与操作指令,并且会更新条件标志位。
- 例如:ANDS R0, R1, #0xF。这条指令将 R1 寄存器的值和立即数 0xF(二进制为 00001111)进行按位逻辑与运算,结果存放在 R0 寄存器中,同时更新条件标志位(N、Z、C、V)。
- ORR:按位进行或运算。如
ORR R12, R13, R14
将R13和R14的每一位进行或操作,结果存入R12,可用于设置某些位的值。 - EOR:执行按位异或操作。例如
EOR R15, R16, R17
把R16和R17按位异或后的结果存到R15,在数据加密等操作中有应用。 - BIC:位清除指令,是在一个字中清除位的一种方法,操作数2是一个32位位掩码。如果在掩码中设置了某一位,则清除这一位,未设置的掩码位指示此位保持不变。
- AND:对两个操作数按位进行与操作。例如,
- 比较指令:
- CMP:用于比较两个操作数的值,它会更新条件标志位,但不存储结果。例如
CMP R1, R2
,通过比较R1和R2的值来设置条件标志,后续可根据这些标志位进行条件跳转等操作。 - CMN:比较两个数的相反数。
- CMP:用于比较两个操作数的值,它会更新条件标志位,但不存储结果。例如
加载/存储指令
- LDR:从内存中将一个32位的数据加载到寄存器中。例如
LDR R0, [R1]
表示从R1所指向的内存地址处读取一个字的数据到R0中。 - STR:将寄存器中的32位数据存储到内存中。例如
STR R2, [R3]
把R2中的数据存储到R3所指向的内存地址。 - LDM:多寄存器加载指令,可以一次性加载多个寄存器的数据。例如
LDMIA R4!, {R5 - R7}
以递增的地址顺序从R4所指向的内存位置加载多个数据到R5 - R7寄存器中,并且R4会根据加载的字节数自动更新。 - STM:多寄存器存储指令,一次性存储多个寄存器的数据。例如
STMDB R8!, {R9 - R11}
以递减的地址顺序将R9 - R11寄存器中的数据存储到R8所指向的内存位置,R8也会自动更新。
MOV 指令
-
立即数移动:可以将一个 8 位的立即数移动到寄存器中。例如MOV R0, #42,将立即数 42 移动到寄存器R0中
-
寄存器间数据移动:把一个寄存器的值移动到另一个寄存器。如MOV R1, R0,将寄存器R0的值赋给R1
-
寄存器与立即数的逻辑操作后移动:先将一个寄存器里保存的值与一个立即数做逻辑运算,然后将结果移动到目标寄存器里。例如MOV R1, R0 or #0x7,将R0与立即数0x7进行逻辑或操作后的结果存入R1
-
寄存器移位后移动:对一个寄存器的值进行移位操作,并将结果存储到另一个寄存器。比如MOV R1, R0, LSL #2,将R0的值左移 2 位后存入R1
分支指令
- B:无条件分支指令,直接跳转到指定的地址。
- 它可以使程序流程无条件地跳转到指定的目标地址。目标地址是通过将指令中的相对偏移量与当前程序计数器(PC)的值相加得到的。
- 示例:B label,其中label是一个标号,表示要跳转的目标位置。假设在一个简单的程序中,有一段初始化代码,完成后想要直接跳转到主程序部分,就可以这样写:
MOV R0, #0 ;初始化操作
MOV R1, #1
B main_loop ;跳转到main_loop标号处的主程序
main_loop:
;主程序代码
-
BEQ:相等则跳转,即当比较结果相等时,跳转到指定地址。
-
BNE:不相等则跳转,当比较结果不相等时,跳转到指定地址。
-
BGE:大于或等于跳转。
-
BGT:大于跳转。
-
BLE:小于或等于跳转。
-
BLT:小于跳转。
-
BL:带链接的相对跳转指令,在跳转前会将当前的PC值保存到链接寄存器R14中,以便后续返回。
- 示例:BL subroutine,当执行这条指令时,程序会跳转到subroutine标号所代表的子程序处,同时把返回地址(也就是BL指令后的下一条指令地址)保存到 LR 中。在子程序结束时,可以使用MOV PC, LR指令返回。
-
BLX:带链接的切换跳转,除了保存PC值到R14外,还可以切换指令集。
- 如果当前处理器处于 ARM 状态,它会先判断目标地址的最低位:若为 1,则切换到 Thumb 状态,并将目标地址与 0xFFFFFFFE 进行与操作得到实际的跳转地址,然后跳转到该地址执行 Thumb 指令;
- 若为 0,则保持 ARM 状态,直接跳转到目标地址执行 ARM 指令 。在跳转之前,会将 PC 的当前值(即 BLX 指令的下一条指令地址)保存到 LR 寄存器中。
- 当子程序执行完毕后,可以通过将 LR 寄存器的值复制到 PC 中来实现返回。
ARM_CODE:
MOV R0, #1
BLX thumb_func ; 跳转到thumb_func,并切换到Thumb状态,保存返回地址到LR
MOV R1, #2
...
thumb_func:
ADD R0, R0, #1
BX LR ; 返回调用处,切换回ARM状态
- BX:切换跳转,用于在ARM和Thumb指令集之间切换。
程序状态寄存器(PSR)处理指令
- MRS:把状态寄存器的值送到通用寄存器。
- 它在特权模式下使用,对于操作系统内核、设备驱动程序等需要访问和修改处理器状态的程序非常重要。
- 例如:MRS R0, CPSR,这条指令将 CPSR 的值传送到 R0 寄存器中。
- 应用:保存处理器状态,异常发生时,处理器状态可能会被改变,保存原始状态有助于在异常处理完成后恢复现场。
IRQ_Handler:
MRS R1, CPSR
; 进行中断处理的其他操作
- MSR:把通用寄存器的值传送到状态寄存器PSR。
- PSR 是一个关键的寄存器,包含了如处理器模式、中断使能位、条件标志位(N、Z、C、V)等重要信息。
- 基本格式有两种:
MSR{cond} psr_fields, #immediate
MSR{cond} psr_fields, Rm
- 其中,
{cond}
是条件码。和其他ARM指令一样,它可以指定指令执行的条件,例如EQ
(相等)、NE
(不相等)等条件。如果不满足条件,指令将不被执行。 psr_fields
表示目标程序状态寄存器的字段。它可以是以下几种:- CPSR(Current Program Status Register):这是当前程序状态寄存器,包含了所有状态信息。
- SPSR(Saved Program Status Register):用于在异常处理过程中保存CPSR的内容,在异常返回时可以恢复处理器状态。
- CPSR_f或SPSR_f:代表访问标志位字段,主要包括N(Negative)、Z(Zero)、C(Carry)和V(oVerflow)这些标志位,用于反映算术和逻辑运算的结果状态。
- CPSR_c或SPSR_c:用于访问控制位字段,像中断使能位、处理器模式位等控制信息都在这里。例如,在ARM处理器中有多种运行模式,如用户模式、系统模式、管理模式等,这些模式的切换就是通过修改控制位来实现的。
- CPSR_s或SPSR_s:访问状态位字段。
- CPSR_x或SPSR_x:访问扩展位字段。
协处理器指令
Arm微处理器可支持多达16个协处理器。用于各种协处理操作。在程序执行过程中,每个鞋处理器只执行对自身的斜处理指令,忽略按摩处理器以及其他协处理器的指令。
Arm的协处理器指令主要用于arm处理器初始化ARM协处理器的数据处理操作,以及 arm处理器的寄存器和谐处理器的寄存器之间进行数据传递。
- CDP、CDP2:协处理器数据处理操作。
- LDC、LDC2:从协处理器取一个或多个32位值。
- STC、STC2:从协处理器中把一个或多个32位值存到内存。
- MCR、MCR2、MCRR:从寄存器送数据到协处理器。
- MRC、MRC2、MRRC:从协处理器传送数据到寄存器 。
异常产生指令
- BKPT:断点指令,用于设置断点,使程序在执行到该指令时暂停,以便进行调试。
- SWI:软件中断指令,用于产生软件中断,将执行转移到内存地址0x00000008处,并切换到管理模式,可用于实现操作系统调用等功能。
3.1.2 指令的条件域
当处理器工作在ARM状态时,几乎所有的指令均根据CPSR中条件码的状态和指令的条件域有条件的执行。当指令的执行条件满足时指令被执行,否则指令被忽略。
ARM指令的条件码
- 定义与作用
- ARM指令的条件码是一种机制,用于根据处理器的状态标志来决定指令是否执行。这些标志存储在程序状态寄存器(PSR)中,主要包括N(Negative)、Z(Zero)、C(Carry)和V(oVerflow)等标志位。通过条件码,程序可以根据之前操作的结果,如比较运算、算术运算等,有条件地执行后续指令,从而实现高效的分支和控制流程。
- 条件码的种类及其含义
条件码共有16种,每种条件码可用两个字符表示。这两个字符可以添加在指令助记符的后面和指令同时使用。- EQ(Equal):当Z标志位被设置为1时满足条件,即表示上一次操作的结果为零。例如,在执行比较指令
CMP R0, R1
后,如果R0
和R1
的值相等,那么Z标志位会被置1,后续带有EQ
条件码的指令就会执行。常用于判断两个数是否相等,如在循环中判断计数器是否达到某个特定值来决定是否退出循环。 - NE(Not Equal):当Z标志位为0时满足条件,意味着上一次操作的结果非零。例如,在
CMP
指令比较两个不相等的寄存器值后,Z = 0,带有NE
条件码的指令可以执行。它可以用于在一组数据中筛选出与特定值不相等的数据。 - CS/HS(Carry Set/High or Same):当C标志位为1时满足条件。在无符号数的算术运算中,比如加法
ADD
指令,如果产生进位,C标志位会被置1。这在处理无符号数的大小比较和加法运算的溢出判断等场景中很有用,例如判断两个无符号数相加是否超过了寄存器所能表示的范围。 - CC/LO(Carry Clear/Low):当C标志位为0时满足条件。例如在减法运算中,如果没有产生借位,C标志位为0,带有
CC/LO
条件码的指令可以执行。 - MI(Minus):当N标志位为1时满足条件,N标志位表示运算结果的符号位。如果运算结果为负数,N标志位会被置1,带有
MI
条件码的指令就可以执行,用于判断运算结果是否为负。 - PL(Plus):当N标志位为0时满足条件,即运算结果为正数或者零,用于区分非负的运算结果。
- VS(oVerflow Set):当V标志位为1时满足条件。在有符号数的算术运算中,如果发生溢出,V标志位会被置1。例如,在有符号数的加法运算中,当两个正数相加结果为负数,或者两个负数相加结果为正数时,V标志位会被置1,带有
VS
条件码的指令就可以执行,用于检测有符号数运算的溢出情况。 - VC(oVerflow Clear):当V标志位为0时满足条件,用于判断有符号数运算没有溢出的情况。
- HI(Higher):满足
C = 1
且Z = 0
的条件。在无符号数比较中,用于判断一个无符号数是否大于另一个无符号数。例如,在CMP
指令比较两个无符号数R2
和R3
后,如果R2
大于R3
,则满足HI
条件,带有HI
条件码的指令可以执行。 - LS(Lower or Same):满足
C = 0
或者Z = 1
的条件。在无符号数比较中,用于判断一个无符号数是否小于或等于另一个无符号数。 - GE(Greater than or Equal):在有符号数比较中,对于
SUB
或CMP
等指令,当N
和V
标志位相同(N == V
)时满足条件。用于判断一个有符号数是否大于或等于另一个有符号数。 - LT(Less than):在有符号数比较中,当
N
和V
标志位不同(N!= V
)时满足条件。用于判断一个有符号数是否小于另一个有符号数。 - GT(Greater than):满足
Z = 0
且N == V
的条件。在有符号数比较中,用于判断一个有符号数是否严格大于另一个有符号数。 - LE(Less than or Equal):满足
Z = 1
或者N!= V
的条件。在有符号数比较中,用于判断一个有符号数是否小于或等于另一个有符号数。
- EQ(Equal):当Z标志位被设置为1时满足条件,即表示上一次操作的结果为零。例如,在执行比较指令
ARM指令的条件码在寄存器中位置
在ARM的程序状态寄存器(PSR)中,条件码标志的存储位置如下 :
- N标志位:位于PSR的第31位,它表示指令结果的符号位。若运算结果为负数,则N标志位被置1;若结果为非负数,则N标志位被置0 。例如,在执行减法操作
R1 - R2
后,如果结果是负数,那么N标志位会被设置为1。 - Z标志位:处于PSR的第30位,当指令的运算结果为零时,Z标志位被置1;反之,若结果不为零,则Z标志位被置0。比如,在执行比较指令
CMP R3, R4
后,若R3
和R4
的值相等,此时Z标志位就会被置为1。 - C标志位:存于PSR的第29位,其设置情况较为复杂,具体有以下几种情形 :
- 在加法(包括比较指令
CMN
)运算中,如果产生无符号溢出,即加法运算的结果超出了无符号数所能表示的范围,C标志位会被置1;否则置0。例如,两个无符号8位寄存器R5
和R6
相加,结果大于255时,C标志位为1。 - 在减法(包括比较指令
CMP
)运算中,若产生借位,C标志位被置1;否则置0。如R7 - R8
时,若R7
的值小于R8
的值,就会产生借位,C标志位为1。 - 对于包含移位操作的非加减运算,C标志位被设置为移位器移出的最后一位。
- 对于其他的非加减运算,C标志位通常保持不变。
- 在加法(包括比较指令
- V标志位:位于PSR的第28位,在有符号数的算术运算中,如果发生符号溢出,即两个有符号数相加或相减的结果超出了有符号数所能表示的范围,且符号位发生错误时,V标志位被置1;否则置0 。比如,两个有符号8位寄存器
R9
和R10
,分别存储的值为127和1,执行加法操作后结果为-128,此时就发生了符号溢出,V标志位会被置为1 。
不同版本的ARM架构以及不同的处理器模式下,PSR寄存器可能会有一些细微的差异,但上述条件码标志位的基本位置和含义是相对固定的.
3.2 ARM指令寻址方式
寻址方式就是处理器根据指令中给出的地址信息来寻找物理地址的方式。
3.2.1· 立即寻址
- 定义
- 立即寻址是ARM指令集中一种基本的寻址方式。在这种寻址方式中,操作数本身作为指令的一部分直接包含在指令代码中,这个操作数被称为立即数。立即数是一个固定的值,在指令执行过程中,处理器直接使用这个包含在指令中的值进行操作,而不需要从寄存器或者内存中获取。
- 格式与示例
- 在ARM指令格式中,立即数通常跟在操作码之后。例如,在指令
MOV R0, #0x12
中,#0x12
就是立即数。这条指令的功能是将十六进制数0x12(十进制为18)传送到寄存器R0中。这里的MOV
是操作码,表示数据传送操作,R0
是目标寄存器,#0x12
是立即数,也就是要传送到R0中的数据。
- 在ARM指令格式中,立即数通常跟在操作码之后。例如,在指令
- 立即数的编码规则
- ARM指令中的立即数并不是任意的32位数值。它是通过一种特定的编码方式来表示的,这种编码方式允许在指令中高效地表示一个8位的常数,并可以通过循环右移偶数位(0、2、4、6、8、10、12、14、16、18、20、22、24、26、28、30)来得到一个32位的立即数。例如,一个合法的立即数可以是
0x0000000F
(它本身就是8位的0xF循环右移0位得到的),但像0x12345678
这样的数就不能直接作为立即数,因为它不符合ARM的立即数编码规则。
- ARM指令中的立即数并不是任意的32位数值。它是通过一种特定的编码方式来表示的,这种编码方式允许在指令中高效地表示一个8位的常数,并可以通过循环右移偶数位(0、2、4、6、8、10、12、14、16、18、20、22、24、26、28、30)来得到一个32位的立即数。例如,一个合法的立即数可以是
- 应用场景
- 常量赋值:常用于初始化寄存器。例如,在设置中断向量表的起始地址时,可能会使用立即寻址来将一个特定的内存地址值赋给寄存器。比如,将中断向量表的起始地址
0x00000000
赋给某个寄存器(假设为R1),可以使用指令MOV R1, #0x00000000
。 - 计数操作:在循环中作为计数器的初始值。比如,实现一个简单的循环,循环次数为10,可使用指令
MOV R2, #10
来初始化计数器R2,然后在循环体中通过递减R2并判断是否为0来控制循环的结束。 - 设置模式位或控制位:在系统初始化或者模式切换时,用于设置处理器的某些控制寄存器的特定位。例如,设置处理器进入某种特权模式,可能需要将一个特定的立即数写入模式控制寄存器的相应位。
- 常量赋值:常用于初始化寄存器。例如,在设置中断向量表的起始地址时,可能会使用立即寻址来将一个特定的内存地址值赋给寄存器。比如,将中断向量表的起始地址
3.2.2 寄存器寻址
- 原理:操作数的值存放在寄存器中,指令中的地址码字段指出的是寄存器编号,指令执行时直接取出寄存器中的值来进行操作。
- 示例:
MOV R1, R2
,这条指令将寄存器R2
的值存入R1
中;SUB R0, R1, R2
则是将R1
的值减去R2
的值,结果保存到R0
。
3.2.3 寄存器移位寻址
- 原理:这是ARM指令集特有的寻址方式。当第2个操作数是寄存器移位方式时,第2个寄存器操作数在与第1个操作数结合之前,先进行移位操作。
- 示例:
MOV R0, R2, LSL #3
,表示将R2
的值左移3位,结果放入R0
中,即R0 = R2 × 8
;`
3.2.4 寄存器间接寻址
- 原理:指令中的地址码给出的是一个通用寄存器的编号,所需的操作数保存在该寄存器指定地址的存储单元中,即寄存器作为操作数的地址指针。
- 示例:
LDR R1, (R2)
,其功能是将R2
指向的存储单元的数据读出并保存在R1
中;
3.2.5 基址寻址
- 原理:将基址寄存器的内容与指令中给出的偏移量相加,形成操作数的有效地址。常用于查表、数组操作、功能部件寄存器访问等。
- 示例:
LDR R2, (R3, #0x0C)
,该指令会读取R3+0x0C
地址上的存储单元的内容,并放入R2
中;
3.2.6 多寄存器寻址
- 原理:一次可传送多个寄存器的值,允许一条指令传送16个寄存器的任何子集或所有寄存器。
- 示例:
LDMIA R1!, {R2-R7, R12}
,这条指令可以将寄存器R2
至R7
、R12
的值保存到R1
指向的存储单元中,并且R1
的值会自动增加,以指向下一个存储单元。
3.2.7 堆栈寻址
- 原理:使用一个专门的寄存器(堆栈指针)指向一块存储区域(堆栈),指针所指向的存储单元即是堆栈的栈顶。根据堆栈的生长方向和指针指向的不同,可以分为满递增、空递增、满递减、空递减四种类型 。
- 示例:
PUSH {R4-R8}
,该指令会将寄存器R4
至R8
的值依次存储到堆栈中,堆栈指针会自动调整;POP {R4-R8}
则是从堆栈中依次弹出数据,并将其存入寄存器R4
至R8
中。
3.2.8 块拷贝寻址
- 原理:多寄存器传送指令用于将一块数据从存储器的某一位置拷贝到另一位置。
- 示例:通过使用特定的指令格式和寄存器组合,可以实现将一段连续的内存数据批量地从一个地址范围拷贝到另一个地址范围,但具体指令因不同的ARM架构和应用场景可能会有所不同 。
3.2.9 相对寻址
- 原理:相对寻址是基址寻址的一种变通方式。由程序计数器
PC
提供基准地址,指令中的地址码字段作为偏移量,两者相加后得到的地址即为操作数的有效地址。 - 示例:
LDR R1, (PC, #8)
,它会从PC+8
所指向的地址中加载数据到R1
中。这种寻址方式常用于实现程序中的相对跳转和位置无关代码。
3.3 ARM指令集补充
3.3.1 直接写跳转指令
概念
在 ARM 架构中,程序计数器(PC)用于保存下一条要执行指令的地址。通过直接向 PC 写入一个新的地址,可以实现程序流程的跳转。这个新地址可以是绝对地址,也可以是相对地址。当向 PC 写入跳转地址时,处理器会在下一个指令周期从新的地址开始取指令并执行,从而改变程序的执行路径。
方式
使用指令直接写入:可以使用一些能够对寄存器进行写操作的指令来修改 PC 的值。
例如,在某些特殊情况下,通过MOV指令直接将目标跳转地址写入 PC。不过这种方式比较少见,因为直接操作 PC 可能会导致一些不可预测的问题,而且在很多 ARM 处理器的指令集中,对 PC 的直接写入有一些限制。
例如,MOV PC, #addr(其中#addr是目标跳转地址),但在实际应用中,这种简单的方式可能因为对齐问题或者指令流水线等因素而不能正常工作。
3.3.2 数据处理指令
ARM指令中的数据处理指令大致可分为以下几类:
- 数据传送指令:
- MOV:将立即数或寄存器中的数据传送到目标寄存器。例如
MOV R1, #0x10
,将立即数0x10传送到寄存器
- MOV:将立即数或寄存器中的数据传送到目标寄存器。例如