一、指令
- 指令的生成过程
- 指令执行过程示例
if (a == 0) {
x = 0;
} else {
x = x + 3;
}
//翻译为
cmp r0,#0
MOVEQ R1,#0
ADDGT R1,R1,#3
指令获取:从Flash中读取 CMP R0, #0,控制器开始执行。
指令解码:解码器解析 CMP 指令,ALU比较R0的值和0。
条件执行:
若条件满足 EQ,执行 MOVEQ,将0放入R1。
若条件满足 GT,执行 ADDGT,将R1加3。
结果存储:将计算结果保存在R1中。
二、ARM的工作模式
- 用户模式(USR模式)
权限:最低
资源:最少
用途:用于执行普通任务,例如应用程序。大部分程序都运行在用户模式下。 - 管理员模式(SVC模式)
权限:高
资源:多
用途:用于执行核心级任务,例如操作系统的核心代码。 - 中断模式(IRQ模式)
权限:高
资源:多
用途:用于执行中断代码,处理普通中断请求。 - 快速中断模式(FIQ模式)
权限:更高
资源:最多
用途:用于快速处理高优先级中断请求。虽然在某些操作系统(如 Linux)中不常用,但它提供了更快的响应时间。 - 数据终止模式(abort模式)
用途:用于处理内存访问错误。当程序尝试访问非法或无效内存地址时,处理器进入该模式以处理异常。
对寄存器的分配情况
- R0-R7 为所有模式所共享;
- R8-R12 有两份, FIQ模式独享一份;
- R13-R14每种模式都有一份;
模式切换过程中,特殊寄存器的作用
CPSR寄存器
- 可以对CPSR的某些位修改而达到想要的效果。不用背,直接查。
三、立即数
- 一条指令,存放常数的区域只有 12bit; 造成的问题是,当指令中出现大常数的时候, 无法存入12bit中,形成 非法指令!
- ARM公司 将12bit分为 低8bit–X,高4bit–Y,最终的结果是 : X<<2Y ,这样的 8bit常数经过偶数位#循环左移#得到的数据,称之为 立即数;
- 0x10E0 是不是立即数----> 否
0x10D0 ----------------- 否
0x10C0 ----------------- 是 - 简便方法是判断基值(立即数的范围是0x00到0xFF。)
1.补全32位
2.最边上的两个1中间间隔不能超过6个数(包括0,也包括逻辑左移时)
3.其次是这少于等于8个数要放在8位中时,只能移动偶数位,才符合立即数标准,左右移动都可以 - 当要存放较大的数时,通常采用伪指令
Ldr r0 ,=0x12345678 @编译器会用真实的指令替换
四、补充一些伪指令
.byte
解释:.byte指令告诉编译器将后面的数据按照字节(1字节)进行存储。
.byte 0x41, 0x42, 0x43 ; 存储ASCII字符'A', 'B', 'C'
char buf[] = {0x41, 0x42, 0x43}; // 初始化字符数组
.word
解释:.word指令用于告诉编译器将后面的数据按照4字节(32位)为单位进行存储。常用于初始化整型数组或表示32位整数。
.word 0x12345678, 0x9ABCDEF0 ; 存储两个32位整数,.word开始的地址就是存放这0x12345678
int xi[] = {0x12345678, 0x9ABCDEF0}; // 初始化整型数组
.equ
解释:.equ伪指令用于定义符号常量。它将某个符号与一个特定的值绑定,这样在代码中可以使用符号来代替具体的数值。
.equ PI, 3.14 ; 将符号PI定义为3.14
五、异常
- 异常(Exception)是指处理器对一些特定事件(例如中断、错误、系统调用等)所做出的响应。异常处理是嵌入式系统中非常重要的一部分,因为它允许系统在发生特定事件时进行处理,从而确保系统的可靠性和稳定性。
1. 异常向量表
异常类型 | 向量地址 | 描述 | 异常模式 |
---|---|---|---|
Reset | 0x00 | 复位异常 | Supervisor |
Undefined Instruction | 0x04 | 未定义指令异常 | Undefined |
SWI | 0x08 | 软件中断 | Supervisor |
Prefetch Abort | 0x0C | 预取指令中止异常 | Abort |
Data Abort | 0x10 | 数据中止异常 | Abort |
IRQ | 0x18 | 普通中断请求异常 | IRQ |
FIQ | 0x1C | 快速中断请求异常 | FIQ |
2. 同时发生时,处理优先级
- 复位(Reset)
处理器上电或者复位时发生的异常 - 数据中止(Data Abort)
数据访问错误时发生的异常,一般是与Memory 误操作有关,如对不合法的内存地址、0地址写操作,或对一些Memory 越界操作。 - FIQ(快速中断请求)
FIQ用于快速响应时间敏感的外部硬件中断,优先级高于IRQ。 - IRQ(普通中断请求)
IRQ用于处理标准的外部硬件中断。优先级低于FIQ。 - 预取指令中止(Prefetch Abort)
在指令预取阶段,如果试图访问的指令地址无效或产生错误,则会触发预取指令中止。 - 未定义指令(Undefined Instruction)
当处理器遇到未定义或不支持的指令时触发。常用于调试和异常捕获。 - SWI(软件中断)
软件中断由SWI指令触发,通常用于执行系统调用或从用户模式切换到内核模式。
3.异常的处理过程
1.流程图(类似于工作模式的切换)
- 异常处理是计算机系统中处理突发事件的关键机制,不同的异常处理需要不同的资源和权限。为了有效处理异常,系统在处理过程中通常会切换到更高权限的模式(如内核模式),这种模式切换由硬件自动完成,确保处理器获得所需的资源和权限。
- 中断异常是异常处理中最重要的类型之一,它能够显著提高系统的响应速度和执行效率。通过快速响应外部事件(如输入输出操作),中断机制使系统能够在需要时中断当前任务来处理更紧急的任务,从而优化资源利用和提升系统性能。
4.中断和异常之间的关系
- 软中断通常也称之为异常,是由处理器内部条件触发的中断。通常由软件指令触发(除数为0),同步发生的。一般用于实现系统调用和任务调度
- 异常是由处理器检测到的错误条件或特殊事件自动触发。软中断可以通过指令主动触发。
- 硬中断也称为真正的中断,硬中断是由硬件设备(磁盘)发出的中断信号,通知处理器有外部事件需要处理。硬中断是异步的,随时发生。
- 正常指令执行 → 检测到异常信号 → 查找异常向量表 → 根据中断向量号获取中断描述符 → 跳转到异常处理程序 → 执行处理例程 → 恢复上下文并返回原程序 → 继续执行
5. 异常向量表的优化
- 问题背景:在ARM异常向量表中,通常需要使用固定偏移来指向异常处理程序。当异常处理程序的地址(例如swi_handle)非常大时,无法直接使用简单的分支指令(如B指令)跳转,因为这些指令可能受限于指令编码长度(通常16位或32位),导致无法存储长地址。
- 解决方案:
采用LDR指令来间接加载处理程序的地址,从而跳转到真正的处理程序位置。这允许在向量表中使用一个更小的跳转指令和更灵活的地址加载方式。 - 实例
b reset @0x0 ; 跳转到复位处理程序
nop ; 无操作,可能用于对齐或延迟
ldr pc, _swi @0x8 ; 从_swi标签处加载地址到PC,跳转到SWI处理程序
nop ; 无操作,占位符
nop
nop
ldr pc, _irq @0x18 ; 从_irq标签处加载地址到PC,跳转到IRQ处理程序
nop ; 无操作,占位符
_swi: @@ _swi 一定要紧贴着 异常向量表,保证 他的值很小
.word swi_handle @0x12345678 ; 存储SWI处理程序的地址
_irq:
; 可能会有类似的定义来加载IRQ处理程序