架构:各种ARM处理器的通用行为特性
处理器: 实现了某种架构,可以集成到不同的设计中
设备:包含处理器和额外组件
ARM架构包括:
编程模型
指令集
系统配置
异常处理
存储模型
一个处理器可以实现不同的内存管理模型:
VMSA(Virtual Memory System Architecture), 基于MMU(Memory Management Unit)
PMSA(Protected Memory System Architecture),基于MPU(Memory Protection Unit)
ARMv7引入了架构的档次(profile):
A 定义了基于VMSA的微处理器架构,高性能,支持操作系统完整特性
R Real-time 定义了基于PMSA的微处理器架构,确定性时间响应和低延迟中断,
M Microcontroller 低延迟的中断处理 拥有不同的异常处理模型和PMSA
处理器
实现某个架构版本
ARM926EJ-S实现了带TEJ扩展的ARMv5
Cortex-A9实现了带multiprocessing扩展的ARMv7-A
设备通常是集成了ARM处理器和额外组件的SOC
实现设备时,缓存大小、是否支持硬件浮点单元等是可选操作;
---------------------ARMv5架构文档摘要-------------------
CPU模式
7种: 用户,管理,系统,中止,中断,快中断,未定义
7种异常:复位 SWI 数据中止 预取中止 快中断 中断 未定义
复位和SWI进入管理模式; 访问不到存储器,进入中止模式(取指令、取数据); 取出的指令无法译码,进入未定义(指令)模式;
只有用户模式是非特权模式,一些存储系统和协处理器的权限受限,通过SWI指令产生异常,切换到另一个特权处理器模式。
特权模式允许对 CPSR完全读写, 非特权模式只能读控制域,读写条件标志。
只有当异常发生时,才保存CPSR(自动?), 用指令来改写CPSR,不会保存到SPSR;
CPSR [NZCV....IFT mode]
I F 中断、快中断屏蔽位
N Negative 来自高31位
Z Zero 结果为0
C Carry 进位;
V 溢出
寄存器:
31个通用寄存器,同一时间只有16个可见R0 ~ R15
r13(SP), r14(LR), r15(PC)
r0....r15 CPSR (用户、系统)
r0...r7 r8_fiq..r14_fiq CPSR, SPSR_fiq (快速中断)
r0...r12 r13_irq r14_irq CPSR, SPSR_irq (中断)
r0...r12 r13_svc r14_svc CPSR, SPSR_svc (管理)
r0...r12 r13_undef r14_undef CPSR, SPSR_undef(未定义)
r0...r12 r13_abt r14_abt CPSR, SPSR_abt (中止)
CP15协处理器控制存储组件:cache,buffer, MMU MPU
条件执行
EQ Z 相等
NE z 不相等
CS/HS C 进位置1/无符号数大于等于
CC/LO c 进位清0/无符号数小于
MI N 负数minus
PL n 非负数plus
VS V 溢出
VC v 无溢出
HI zC 无符号大于
LS Z/c无符号小于等于
GE NV/nv 有符号大于等于
LE Z/Nv/nV 有符号小于等于
GT NzV/nzv 有符号数大于
LT Nv/nV 有符号数小于
流水线
ARM模式”执行“当前指令时,PC寄存器已经指向了 +8 的位置;
跳转指令时,ARM核清空流水线; 但通过分支预测技术,可提前装载分支地址,减小影响;
中断时,当前执行的指令要完成,流水线中的其他指令丢弃;
典型ARM指令有两个源寄存器Rn,Rm,1个目的寄存器, 其中Rm可在进入ALU前做移位预处理。
语法: ADD r3,r2,r1 r3目标, r2、r1源寄存器;
指令分类:数据处理,分支,LOAD-STORE,中断,程序状态寄存器
数据处理指令(MOV,算术,逻辑,比较,乘法)
数据处理指令前使用S后缀,将会更新CPSR中的标志位(N Z C V);CMP不需要加S,自动更新CPSR;
MOV指令和逻辑指令会对C,N,Z产生影响;
MOV语法: <指令>{<cond>}{S} Rd, N
MOV Rd,N ; Rd = N
MVN Rd,N ; Rd = ~N
语法中的N可以是寄存器、立即数,也可以是桶形移位器预处理的寄存器Rm,如: R0, LSL #2
桶形移位器,在操作数进入ALU之前,对操作数进行指定位数的左/右移,这发生在当前的指令周期内;
MOV r7, r5, LSL #2 ; r7 = r5<<2
LSL 逻辑左移 x LSL y x<<y
LSR 逻辑右移 x LSR y (unsigned)x>>y
ASR 算术右移 x ASR y (signed)x>>y 只有算术右移才是有符号;
ROR 循环右移 x ROR y ((unsigned)x>>y) | (x<<(32-y))
RRX 扩展循环右移1位 x RRX y (c << 31) | ((unsigned)x>>1) CPSR中的C标志位;
算术指令
<指令>{<cond>}{S} Rd, Rn, N
ADD 32位加法 Rd = Rn + N
ADC 32位加法带进位 Rd = Rn + N + carry
SUB 32位减法 Rd = Rn - N
SBC 32位减法带进位 Rd = Rn - N - !C
RSB 逆向减法 Rd = N - Rn
RSC 逆向减法带进位 Rd = N - Rn - !C
逻辑指令
<指令>{<cond>}{S} Rd, Rn, N
AND Rd = Rn & N 逻辑与
ORR Rd = Rn | N 逻辑或
EOR Rd = Rn ^ N 逻辑异或
BIC Rd = Rn & ~N 逻辑位清除
比较指令(自动更新CPSR)
<指令>{<cond>} Rn, N
CMP Rn - N 比较
CMN Rn + N 取负比较
TEQ Rn ^ N 相等测试
TST Rn & N 位测试
乘法指令
MLA {<cond>}{S} Rd,Rm,Rs,Rn ; Rd=(Rm*Rs)+Rn 乘累加
MUL {<cond>}{S} Rd,Rm,Rn ; Rd=Rm*Rn 乘法
<指令> {<cond>}{S} RdLo,RdHi, Rm,Rs
RdLo低32位,RdHi高32位;S有符号 U无符号,尾部L长整型
SMLAL [RdHi,RdLo] = [RdHi,RdLo] + Rm*Rs
SMULL [RdHi,RdLo] = Rm*Rs
UMLAL [RdHi,RdLo] = [RdHi,RdLo] + Rm*Rs
UMULL nb[RdHi,RdLo] = Rm*Rs
分支指令
B{<cond>} label
BL{<cond>} label
BX{<cond>} Rm
BLX{<cond>} Rm | label
B pc=label跳转
BL pc=label,lr=BL后的第一条指令地址
BX pc=Rm&0xFFFFFFFE, T=Rm&1 跳转并切换状态
BLX pc=label,T=1;
pc=Rm&0xFFFFFFFE,T=Rm&1, lr=BLX后面第一条指令的地址
label为有符号相对PC的偏移量,限制在32MB范围内;T对应CPSR中的Thumb位;
BX/BLX中的Rm为绝对地址,最低位表示是否切换到Thumb状态;
LOAD-STORE指令
单寄存器传送
<LDR|STR>{<cond>}{B} Rd, addressing1
LDR{<cond>}SB|H|SH Rd, addressing2
STR{<cond>}H Rd,addressing2
LDR 把一个字装入一个寄存器
STR 从一个寄存器保存一个字
LDRB 一个字节装入寄存器
STRB 从寄存器保存一个字节
LDRH 加载半字
STRH 存储半字
LDRSB 加载有符号字节
STRSH 存储有符号字节
LDR r0, [r1]; r1指向的数据加载到r0
STR r0, [r1]; r0存储到r1指向的位置, r1称为基址寄存器]
单寄存器LOAD-STORE指令的寻址方式
LDR r0, [r1,#4]! ; r1=r1+4;r0=*(r1);
LDR r0, [r1,#4] ; r0=*(r1+4);
LDR r0, [r1], #4 ; r0=*r1; r1=r1+4
总结:加载的数据总是[]内指向的数据;外面带!或带偏移量的,要回写基址寄存器。
变体:
LDR r0, [r1,r2] ;
LDR r0, [r1,r2, LSR #0x04]! 加载mem32[r1+(r2 LSR #0x04)],r1 = r1 + (r2 LSR 0x4)
LDR r0, [r1,-r2,LSR #0x4] 加载mem32[r1-(r2 LSR #0x04)]
LDR r0, [r1], r2, LSR #0x04 加载mem32[r1], r1=r1+(r2 LSR 0x4)
多寄存器传送
增加中断的延迟;
{LDM|STM}{<cond><寻址模式>Rn{!}, <Registers>{r^}
LDM {Rd}*N < mem32[base+4*N] 可选Rn更新; 加载内存到多个寄存器
STM {Rd}*N > mem32[base+4*N] 可选Rn更新; 保存多个寄存器到内存
----寻址模式 描述 起始地址 结束地址 Rn! ----
IA 执行后增加 Rn Rn+4*N-4 Rn+4*N
IB 执行前增加 Rn+4 Rn+4*N Rn+4*N
DA 执行后减少 Rn-4*N+4 Rn Rn-4*N
DB 执行前减少 Rn-4*N Rn-4 Rn-4*N
I增加,D减少;
执行后增加: 先从相关地址加载数据,再更新下一步要加载数据的地址
LDMIA r0!, {r1-r3}
STMIB r0!, {r1-r3}
堆栈操作
ATPCS定义堆栈为满递减式,LDMFD,STMFD分别对应pop和push
A(Ascending), D(Descending); F(Full)sp指向的位置已使用; E(Empty)sp指向的位置未使用;
FA ----> Full Ascending 满递增堆栈
FD ----> Full Descending 满递减堆栈
EA ----> Empty Ascending 空递增堆栈
ED ----> Empty Descending 空递减堆栈
交换指令
SWP{B}{<cond>} Rd,Rm,[Rn] ; tmp=mem32[Rn]; mem32[Rn]=Rm;Rd=tmp;
SWPB 字节交换
执行期间不能被其他指令或任何总线访问打断,在此期间系统”占据总线(hold the bus)”
交换指令用于实现操作系统中的信号量和互斥操作;
软中断指令
通常在用户模式下执行,用于系统调用;
SWI{<cond>} SWI_Number
1. lr_svc = SWI后面的指令地址
2. spsr_svc = cpsr
3. pc=vectors+8
4. cpsr = svc
5. cpsr_I = 1 (屏蔽IRQ中断)
小结:设置CPU模式和中断屏蔽位, 跳转到相应中断处理函数;
程序状态寄存器指令
MRS{<cond>} Rd, <cpsr|spsr> ; Rd = psr
MSR{<cond>} <cpsr|spsr>_<fields>, Rm ; psr[field] = Rm
MSR{<cond>} <cpsr|spsr>_<fields>, #immediate ; psr[field] = immediate
MRS r1, cpsr
BIC r1, r1,#0x80
MSR cpsr_c,r1
协处理指令
用于扩展指令集。既可用于提供附加的计算能力,又可用于控制包括Cache和内存管理的存储子系统。
包括数据处理、寄存器传输及内存传输指令。 指令和具体的协处理器相关。
CDP {<cond>} cp,opcode1,Cd,Cn {,opcode2}
<MRC|MCR>{<cond>} cp,opcode1,Rd,Cn,Cm{,opcode2}
<LDC|STC>{<cond>} cp,Cd,addressing
CDP 协处理器数据处理,在协处理器内部进行一个数据处理操作;
MRC MCR协处理器寄存器传输, 把数据送入或取出协处理器寄存器;
LDC STC 协处理器内存传输,从协处理器加载/存储一个内存数据块;
cp代表协处理器编号,范围p0-p15。
CP15为系统预留,用于内存管理,写缓冲控制、Cache控制及寄存器识别。
协处理器15(CP15)指令
CP15系统控制协处理器。
可配置处理器核,有一组专用的寄存器用于存储配置信息
MRC p15,0,r1,c1,c0,0 ; 把C1写到r1中去
常量加载
ARM指令是32位,用于存储立即数的占12位(4位偏移量加8位整数)
ARM增加了两条伪指令,用于把32位常量送入寄存器。让编译器或汇编器来选择实际的指令。
LDR Rd, =constant ;常量装载
ADR Rd, label ;地址装载
零计数指令
计算最高符号位与第一个1之间零的个数。
LDR r1,=0x00FFFFFF
CLZ r0,r1 ; r0=8
=======================================
异常和中断处理
异常是需要中止指令正常执行的任何情形。中断是一种特殊的异常;
每种异常都导致处理器进入一种特定的模式。除此之外,改CPSR也可以进入特定模式。
一个异常导致模式改变时,内核自动地:
1. 保存CPSR到相应异常模式的SPSR;
2. 保存PC 到相应异常模式的LR;
3. 设置CPSR为相应异常模式;
4. 设置PC 为相应异常处理程序的入口地址。
异常及 对应模式
----------------------
快速中断 FIQ
中断 IRQ
SWI/复位 SVC
预取/数据中止 abort
未定义指令 undefined
向量表(异常发生时,跳转地址组成的表)
B 相对PC的分支跳转
LDR pc, [pc,#offset]
LDR pc, [pc,#-0xFF0]
MOV pc, #immediate
向量表及处理器模式
异常 模式 偏移
-------------------------
复位 SVC 0x0
未定义指令 UND 0x4
SWI SVC 0x08
预取指中止 ABT 0x0C
数据中止 ABT 0x10
未分配 --- 0x14
IRQ IRQ 0x18
FIQ FIQ 0x1C
异常优先级
异常 优先级 I位 F位
------------------------------
复位 1 1 1
数据中止 2 1 -
FIQ 3 1 1
IRQ 4 1 -
预取指中止 5 1 -
SWI 6 1 -
未定义指令 6 1 -
异常发生时,LR被设置成为基于当前PC值的一个特定值。
IRQ时,LR=最后执行的指令地址加8; LR保存的是异常处理程序的返回地址。
基于LR寄存器的有用地址
异常 地址 用法
------------------------------
复位 --
数据中止 lr-8 指向导致数据中止异常的那条指令
FIQ lr-4
IRQ lr-4
预取指中止 lr-4
SWI lr 指向SWI指令的下一条指令
未定义指令 lr 指向未定义指令的下一条指令
handler
<handler code>
...
SUBS pc, r14, #4 ;pc=r14-4.
SUBS尾部有一个【S】, 并且PC是目的寄存器,SPSR自动恢复到CPSR
汇编示例,用write系统调用输出 "hello"并调用exit退出:
.section .data
hello:
.ascii "hello\n"
.section .text
.globl _start
_start:
mov r0, #1 //fd 1 stdout
ldr r1, =hello //buf addr
mov r2, #6 //size 6
mov r7, #4 //syscall write
svc #0
mov r0, #0 // exit status 0
mov r7, #1 // syscall 1(exit)
svc #0
all:
as -g main.s -o main.o
#ld -dynamic-linker /lib/ld-linux-aarch64.so.1 -lc main.o -o a.out
ld main.o -o a.out
rm main.o