关于ARM寄存器组及工作
模式知识
(周方辉)
2012/8/10 编改记录
目录
1 参考文献 (2)
1.1 内部参考文献 (2)
1.2 外部参考文献 (2)
2 名词解释 (2)
3 ARM核工作模式 (2)
3.1 程序状态寄存器 (3)
3.2 寄存器分组 (4)
3.3 何为特权(异常)模式 (6)
3.4 各种模式工作机制 (7)
3.5 各种模式工作返回用户模式机制 (9)
4 ARM核工作模式初始化参考代码 (11)
1参考文献
1.1内部参考文献
内部参考文献指的是周方辉自生的百度博文中的文件。
无内部参考文献。
1.2外部参考文献
外部参考文献指的是相对于上述内部参考文献以外的文件。
《ARMv8_ISA_PRD03-GENC-010197-24-0.pdf》
《cortex_a8_r3p2_trm.pdf》
《CortexA8TechRefManul.pdf》
2名词解释
CPSR:当前程序状态寄存器,其数值反映出当前程序运行的一些状态指示。
SPSR:保存程序状态寄存器,在程序调用等情况下,需要保存一下当前程序状态寄存器的值(SPSR<=CPSR),便于日后回复。
SP:堆栈指针寄存器,其值用于执行当前堆栈栈顶(或栈底)位置。
PC:程序指针寄存器,其值用于指向要执行的程序代码地址。
LR:连接返回寄存器,保存要返回的地址,PC<=LR。
3ARM核工作模式
常规CPU工作核心模块都是由:寄存器组和ALU两大模块组成,ALU完成数据的加工处理,寄存器用来保存数据,这些数据是直接参与ALU运算。ARM的处理器也不例外。
ARM处理器的寄存器分成许多组,不同的组完成不同环境下的工作,不过它们都共用一套ALU数据处理模块。ARM寄存器一般用了37个,Cortex A8的ARM核的寄存器多大40个。
我们学习ARM工作模式需要了解和解决下面问题:
ARM寄存器为什么要分组?又是如何分组?
各组与CPU工作模式是如何关联?
各个组或工作模式是如何切换的?
我们在学习ARM寄存器分组工作模式之前,先来看一下很特殊的一个寄存器——PSR 程序状态寄存器。
3.1程序状态寄存器
程序状态寄存器是一个32bits的寄存器,它记录和指示出当前程序运行状态。
格式如下:
条件状态位:
N:Negative/Less than,负数/小于0,而置1。
Z:Zero,为0时该位置1。
C:Carry/Borrow/Extend,发生了进位/借位/扩伸,该位将置1。
V:Overflow,溢出时该位置1。
它们之间关系:
Q:Sticky overflow,饱和计算溢出标志。(有符号运算,确保数的极性不会翻转)发生时溢出,该位置1。例如:假设8bits符号数据,125+9=127,133超过127成为负数,而Q算法保持127最大数,确保不会变成负数。
IT[7:0]:[7:2]用于IF….ELSE…条件执行状态位。
GE[3:0]:用于SIMD指令,大于或等于。
使能控制位:
A:A=1时,禁止不确定数据异常。
I:IRQ中断使能位,当其置1时,禁止IRQ发生。
F:FIQ中断使能位,当其置1时,禁止FIQ中断。
指令类别状态位:
J:Java state bit,当T为1时,J=0,表示执行Thumb指令状态,J=1表示执行ThumbEE 指令状态。
T:当其为1是表示执行Thumb指令状态(或ThumbEE,这依赖于J为要为1),当其为0时,表示执行ARM指令状态。
工作模式位:用来指示不同组寄存器与ALU协同工作
M[4:0]:工作模式,
b10000(0x10)用户模式(User);
b10001(0x11)快速中断模式(FIQ);
B10010(0x12)向量中断模式(IRQ);
B10011(0x13)管理模式(Supervisor);
B10111(0x17)异常模式(Abort),取数据失败时发生;
B11011(0x1B)未定义模式(Undefined),指令解码出错时发生;
B11111(0x1F)系统模式(System)
B10110(0x16)安全监视模式(Secure Monitor),主要用于安全交易。
E:大端和小端标志,0小端,1为大端存储。因为ARM总线都为32bits(4个字节)以上的,而数据的存取常规以8bits为(字节)单位,这样就会出现如何放置数据问题。
规定数据高位放在高字节,低位的放在低字节的成为小端存取;反之,称之为大端存取。
3.2寄存器分组
ARM芯片将寄存器分成很多个组,来运行不同模式下的程序,让CPU程序运行得更加稳健。
下图是ARM寄存器分组图:User、System、FIQ、Supervisor、Abort、IRQ、Undefined
和Secure monitor共8个组。其中User和System两个组的寄存器完全共用,Secure monitor 是Cortex A8的ARM核开始追加的模式。
8中寄存器各自拥有和可访问的寄存器:
其中17个寄存器是各个组共用,(特别是R0---R7是每个组都共用的,另外R8和R14在FIQ 模式中不共用,FIQ有自己的R8_fiq---R14_fiq替代它们),另外专多达23个专用的寄存器分散在各种模式组中。
另外,许多寄存器都有专门用途,并且使用别名来操作。例如:
R9->SB,静态基地址寄存器。
R10->SL,数据堆栈限制指针。
R11->FP,(frame pointer) 帧指针。
R12->IP,(Intra-Procedure-call Scratch Register)子程序内部调用暂存寄存器。
R13->SP,堆栈指针stack pointer
R14->LR,连接寄存器linker register,用于跳转后返回(PC<-LR)。
R15->PC,程序计数器program counter,用于指向程序执行代码。
ATPCS规则就使用了上述别名。
3.3何为特权(异常)模式
这8组寄存器中,处理User外,其余7中都为特权模式或异常模式。我们可以给特权模式作如下规定:
1、对PSR寄存器中的模式位组有修改能力。
2、除了能访问共用寄存器外,还有自己的一些专用寄存器(System特权模式除外)。目前为止,除了User模式外,其它的都属于特权模式。
何为异常模式:
1、异常模式都属于特权模式的类别。
2、都有自己的专用模式处理程序入口地址(又称异常向量表),为CPU提供实时高效
和智能服务。
虽然也是8(8x4=32字节)个地址(存放指令,仅有一条,多数为跳转指令),但是它们与8
我们发现,8中模式中Supervisor和Abort各占用了两个表项,而User、System和Monitor 没有任何关联,这是为什么?
其一User模式是程序正常运行模式,它不需要进行特殊的异常处理,即User不是异常模式,所以它没有占任何表项;
另外System是特权模式,但是它不是异常模式,所以也不需要占用任何表项,System 与User完全共用寄存器,同时有能力进行模式切换(修改PSR寄存器的模式位),所以它是其它特权模式与User模式的交互桥梁。
对于Secure Monitor模式来说,是安全模式,需要协处理器来启动该模块,方能工作。同时又并在8种模式之中,我推测,Reserved会留给该异常模式使用,但是需要认证。
何为中断模式:
1、属于异常模式。
2、ARM核用来接入核外部的异常事件,称之为中断,FIQ和IRQ两种。
各种模式关系图:
3.4各种模式工作机制
工作模式切换2种方式:
1、程序手动切换,在某种特权模式下,可以切换到另外一个特权模式下,不过User用户
模式没有这个能力,因为它不是特权模式。
2、异常切换,异常事件发生,可从User模式下切换到异常模式下,或从另外一种异常模
式下切换到该异常事件模式下。
CPSR、PC和SPSR_xxx、LR_xxx寄存器工作关系:
当发生异常时:LR_xxx将保存但前PC值,SPSR_xxx将保存CPSR,因为PC会继续存放异常模式下的指令地址,CPSR将继续反应异常模式下程序运行状态,所以要保存。发生异常时,这些动作硬件自动完成。
同理:当异常程序结束时,CPSR<=SPSR_xxx,PC<=LR_xxx,恢复正常程序运行。
各种SPSR_xxx进入模式时备份CPSR用,各种LR_xxx用来保存PC。退出异常时,用户在异常程序的末尾写入一条完成PC<=lr指令,就自动完成CPSR<=SPSR_xxx动作。
CPSR——〉SPSR_xxx和PC+4——〉LR_xxx为一条指令完成,并非两条指令;同理
SPSR_xxx——〉CPSR和LR_xxx——〉PC也是一同指令一气呵成完成。
R13_xxx寄存器用途(sp_xxx堆栈指针):
指示相应异常模式下,私有堆栈空间,该堆栈可以完成异常模式下函数程序的切换参数传递。
FIQ和IRQ特权模式(异常或叫中断模式):
这两个特权模式是为Cortex-A8核以外的异常提供了处理接口。如按键、ADC转换成功和RTC等,这类相对Cortex-A8核来说(虽然这所有模块可能跟CortexA8一起都在一颗芯片上,如S5PC100)是外部打断了Cortex-A8核的正常运行,所以又称之为FIQ和IRQ中断模式。
Cortex-A8对FIQ和IRQ中断是否响应,在CPSR中有F和I位来控制,它们值为0表示允许响应,为1表示禁止响应,即FIQ和IRQ是可屏蔽中断,但是不能禁止中断事件发生,只是Cortex-A8内核不做响应而已。
Supervisor特权模式(异常):
进入Supervisor异常模式,一般有两种方式:硬件方式芯片复位(上电复位和复位引脚引发)和软件方式执行swi指令。
Abort特权模式(异常):
Abort异常模式,有Cortex-A8内部硬件自动引发,对内存数据的存取和指令预取失败会引发该异常。
Undefined特权模式(异常):
Undefined异常,由Cortex-A8内部硬件自动引发,当执行一条无法识别的指令时,将发生该异常。
Secure Monitor特权(异常)模式:
Secure monitor异常,当有私密的数据程序(如货币交易)要执行时,用户软件调用SMI (SMC替代SMI指令)指令即可进入该模式。
System特权模式:
System特权模式是Cortex-A8的7个特权模式中唯一一个没有自己的程序入口地址,所以它不属于异常概念。Systemt特权模式有两个特点:
1、System特权模式下的工作寄存器与User用户模式下的寄存器完全一样,不多一个,
也不少一个。
2、System特权模式能操作CPSR_mod权限,也就是说可以切换各种特权模式,访问他
们的资源。
上述特点使得System特权模式为其它6种特权(异常)模式下访问User模式下的资源。也就是说,在6种异常特权模式下,通过将CPSR_mod设置成System模式下,来访问User模式下资源,完成后,再将CPSR_mod改回去就恢复原有异常模式。
默认嵌套是禁止的。
Thumb Execution Environment(ThumbEE),在Thumb-2基础上发展起来的,2005年发布,为Java之类服务。
进阶SIMD(NEON)64bit和128bit单指令多重指令集(SIMD)。
期中用户模式和系统模式共用寄存器组,为用户模式进入伪特权提供机制。
ARM中各个异常处理响应优先级:
Reset(Supervisor),优先级最高。
Data Abort,优先权次之。
FIQ,优先级排到第3位。
IRQ,优先级排到第4位。
Prefetch Abort,优先级排到第5等级
SWI,优先级排到第6等级。
Undefined,优先级低7位。
Secure Monitor,优先级最低。
3.5各种模式工作返回用户模式机制
异常程序相关的代码行为原则:
1.MOVS PC,LR 当PC作为目的寄存器时,S 表示pc给lr的同时,恢复SPSR_
2.从SWI(管理模式)和undef异常返回:MOVS PC,LR
3.从FIQ, IQR和预取异常(prefect abort)返回:subs pc, lr, #4
4.从数据异常(Data Abort)返回:SUBS PC, LR, #8
5.如果LR之前被压栈的话使用LDM “^”: LDMFD SP ! , {PC}^
1、发生中断时,将CPSR保存到SPSR_xxx中,改变CPSR_mod,将返回地址保存到LR_xxx
中,将PC指向相应的中断向量地址。
2
注意:如果LR之前是被压入栈的,就用LDMxx sp!,{pc}^指令返回。
3、同时将SPSR_xxx恢复到CPSR中。
来自《CortexA8TechRefManul.pdf》文件如此描述:
《ARM_UAL.pdf》中给出,现在版本中使用SMC来替代SMI,同时也用SVC替代SWI
4ARM核工作模式初始化参考代码
以《S5PC100》的芯片内核为代表:
/*
*文档作用:A8芯片启动程序,使用汇编编写。
*/
.equ ELFIN_CLOCK_POWER_BASE, 0XE0100000
.equ GPG3CON, 0XE03001C0
.equ APLL_MASK_OFFSET, 0x00
.equ MPLL_MASK_OFFSET, 0X04
.equ EPLL_MASK_OFFSET, 0X08
.equ HPLL_MASK_OFFSET, 0X0C
.equ CLK_DIV0_OFFSET, 0X300
.equ CLK_DIV0_MASK, 0X3FFF
.equ CLK_DIV0_VAL, ((1<<0)|(0<<4)|(3<<8)|(1<<12)|(1<<16)) .equ APLL_CON_OFFSET, 0X100
.equ CLK_DIV1_VAL, ((1<<16)|(1<<12)|(1<<8)|(1<<4))
.equ CLK_DIV1_OFFSET, 0x304
.equ APLL_VAL, (1<<31 | 445<<16 | 4<<8 | 0)
.equ MPLL_VAL, (1<<31 | 89<<16 | 2<<8 | 1)
.equ EPLL_VAL, (1<<31 | 90<<16 | 3<<8 | 3)
.equ HPLL_VAL, (1<<31 | 133<<16 | 6<<8 | 2)
.equ CLK_SRC0_OFFSET, 0x200
.equ GPG3DAT, 0XE03001C4
.equ MPLL_CON_OFFSET, 0X104
.equ EPLL_CON_OFFSET, 0X108
.equ HPLL_CON_OFFSET, 0X10c
.extern mmu_setmtt;
.text
.global _start
_start:
b reset
ldr pc,_undefined_instruction
ldr pc,_software_interrupt
ldr pc,_prefetch_abort
ldr pc,_data_abort
ldr pc,_not_used
ldr pc,_irq
ldr pc,_fiq
_undefined_instruction:.word _undefined_instruction @空操作_software_interrupt:.word _software_interrupt @空操作
_prefetch_abort:.word _prefetch_abort @空操作
_data_abort:.word _data_abort @空操作
_not_used:.word _not_used @空操作
_irq:.word IRQ_Handler
_fiq:.word _fiq @空操作
reset:
@加载基地址《DDIO344k_cortex_A8_r3p2_tra.pdf中P94》
ldr r0,=0x34000
mcr p15,0,r0,c12,c0,0
@设置处理器访问权限,能访问特权和用户模式
m ov r0, #0xfffffff
mcr p15, 0, r0, c1, c0, 2
@设置EN=1,使用NEON和VFP模块
m ov r0, #0x40000000
fmxr fpexc, r0
@进入SVC模式
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
ldr r0,=GPG3CON @init gpio for led
ldr r1,=0x1111
str r1,[r0]
/* 关闭WTD */
ldr r0,=0xea200000
mov r1,#0
str r1,[r0]
/*
* 初始化 core clock 和 bus clock.
*/
@《P166》输入时钟12MHz,屏蔽时间参数3600(0xE10)=300uS
ldr r0, =ELFIN_CLOCK_POWER_BASE /*0xe0100000*/@加载时钟配置寄存器的基地址
mov r1, #0xe00
orr r1, r1, #0x10@r1=0x310屏蔽时间值0.3mS
str r1, [r0, #APLL_MASK_OFFSET] @APLL_MASK=0xE10
str r1, [r0, #MPLL_MASK_OFFSET] @MPLL_MASK=0xE10
str r1, [r0, #EPLL_MASK_OFFSET] @EPLL_MASK=0xE10
str r1, [r0, #HPLL_MASK_OFFSET] @HPLL_MASK=0xE10
@设置CLK_DIV0(0xE010_0300)寄存器《P173》
@分频设置
@DOUTAPLL=MOUTapll/2
@ARMCLK = DOUTapll / 1,
@HCLK0 = DOUTarm / 4,
@PCLK0 = HCLK0 / 2,
@HCLK0_SECSS=DOUTd0_bus/2
ldr r1, [r0, #CLK_DIV0_OFFSET]
ldr r2, =CLK_DIV0_MASK
bic r1, r1, r2
ldr r2, =CLK_DIV0_VAL @(1<<16 | 1<<12 | 3<<8 | 0<<4 | 1<<0) orr r1, r1, r2
str r1, [r0, #CLK_DIV0_OFFSET]
@设置APLL_CON(0xE010_0100)寄存器《P167》
@将0x81bd0400(MDIV=0x1bd(445),SDIV=0,PDIV=4)值赋给APLL_CON寄存器@实现FOUTAPLL=(MDIV*(FIN/PDIV))/2^SDIV=1335MHz(50MHz到2000MHz)
ldr r1, =APLL_VAL @(1<<31 | 0x1bd<<16 | 0x4<<8 | 0)
str r1, [r0, #APLL_CON_OFFSET]
@设置CLK_DIV((0xE010_0304)寄存器《P174》
@DOUTAPLL2 = MOUTAPLL / 1
@DOUTMPLL = MOUTAMPLL / 2
@DOUTMPLL2 = MOUTAMPLL / 2
@DOUTD1_BUS= MOUTAMPLL / 2
@PCLK = DOUTD1_BUS / 2
ldr r1, [r0, #CLK_DIV1_OFFSET]
ldr r2, =CLK_DIV1_VAL
@CLK_DIV1_VAL=((1<<16)|(1<<12)|(1<<8)|(1<<4))=0x11110
orr r1, r1, r2
str r1, [r0, #CLK_DIV1_OFFSET]
@设置MPLL_CON(0xE010_0104)寄存器《P168》
@将0x80590201(MDIV=0x59(89),SDIV=1,PDIV=2)值存入到MPLL_CON寄存器中
@实现FOUTMPLL=(MDIV*(FIN/PDIV))/2^SDIV=267MHz(10MHz到600MHz之间)
ldr r1, =MPLL_VAL @MPLL_VAL=(1<<31 | 89<<16 | 2<<8 | 1)=0x80590201
str r1, [r0, #MPLL_CON_OFFSET]
@设置EPLL_CON(0xE010_0108)寄存器《P168》
@将0x805a0303(MDIV=0x5A(90),PDIV=3,SDIV=3)值保存到EPLL_CON寄存器中
@FOUTEPLL=(MDIV*(FIN/PDIV))/2^SDIV=45MHz
ldr r1, =EPLL_VAL @EPLL_VAL=(1<<31 | 90<<16 | 3<<8 | 3)=0x805a0303
str r1, [r0, #EPLL_CON_OFFSET]
@设置HPLL_CON(0xE010_010C)寄存器《P168》
@将0x80850602(MDIV=0x85(133),PDIV=6,SDIV=2)值保存到HPLL_CON寄存器中@FOUTHPLL=(MDIV*(FIN/PDIV))/2^SDIV=66MHz
ldr r1, =HPLL_VAL @HPLL_VAL=(1<<31 | 133<<16 | 6<<8 | 2)=0x80850602
str r1, [r0, #HPLL_CON_OFFSET]
@设置CLK_SRC0(0xE010_0200)寄存器《P169》
@CLK_SRC0[0]=1:FOUTAPLL MOUTAPLL =1335MHz
@CLK_SRC0[4]=1:FOUTMPLL MOUTMPLL =267MHZ
@CLK_SRC0[8]=1:FOUTEPLL MOUTEPLL =45MHz
@CLK_SRC0[12]=1:FOUTHPLL MOUTHPLL =66MHz
ldr r1, [r0, #CLK_SRC0_OFFSET]
ldr r2, =0x1111 @(1<<12 | 1<<8 | 1<<4 | 1 <<0)
orr r1, r1, r2
str r1, [r0, #CLK_SRC0_OFFSET]
@延时
mov r1, #0x10000
1:subs r1, r1, #1
bne 1b
init_stack:
ldr r0,stacktop /*get stack top pointer*/ /********svc mode stack********/
mov sp,r0
sub r0,#128*4 //512 byte for irq mode of stack /****irq mode stack**/
msr cpsr,#0xd2
mov sp,r0
sub r0,#128*4 //512 byte for irq mode of stack /***fiq mode stack***/
msr cpsr,#0xd1
mov sp,r0
sub r0,#128*4
/***abort mode stack***/
msr cpsr,#0xd7
mov sp,r0
sub r0,#128*4
/***undefine mode stack***/
msr cpsr,#0xdb
mov sp,r0
sub r0,#128*4
/*** sys mode and usr mode stack ***/
msr cpsr,#0x10
mov sp,r0 //2560 byte for user mode of stack
b main
.align 4
IRQ_Handler:
sub lr,lr,#4
stmfd sp!,{r0-r12,lr}
bl Entry_IRQ4C
ldmfd sp!,{r0-r12,pc}^
stacktop:.word stack+8*512
.data
stack: .space 8*512