浅谈ARM处理器工作模式&内核寄存器&指令语句

ARM处理器工作模式

工作模式解释
User(USR)非特权模式,大部分任务执行在这种模式
System(特权)和User共用寄存器的特权模式
FIQ(特权)快速中断模式
IRQ(特权)低速中断模式
Supervisor(特权)(SVC)复位或者软中断的工作模式
Abort(特权)(ABT)预取异常的工作模式
Undef(特权)(UND)未定义指令的工作模式
Moniter(Cortex-A)(MON)执行安全监控代码的模式
Hyp(HYP)Implemented with Vituralization Extensions

ARM内核寄存器组

寄存器
R0
R1
R2
R3
R4
R5
R6
R7
R8
R9
R10
R11
R12
SP(R13)
LR(R14)
PC(R15)
CPSR
SPSR
ELR_hyp
模式User/SystemHypSupervisorAbortUndefMoniterIRQFIQ
  • User与System模式共用所有的寄存器,其他模式共用R0~R12寄存器。

  • CPSR为当前程序状态的寄存器。

  • SPSR为保存程序状态的寄存器。

  • SP为栈指针寄存器,满栈式压栈指向最后压栈时的地址,此时指向的地址内部有数据,空栈式压栈指向最后压栈时的地址-4(即栈顶上面),此时指向的地址内部无数据。

  • LR为链接寄存器,指向的时函数执行完毕后的返回地址,也就是所谓的程序跳转断点。

  • PC为程序计数器,指向当前的机器码。

CPSR寄存器

以下寄存器位由高至低,[31:0]。

寄存器位置1时的含义
NALU的结果位负数
ZALU的结果为0
CALU操作进位/借位
VALU操作溢出
Q累计饱和(也称为粘性),饱和:不循环
IT[1:0]
J内核是否处于Jazelle状态
空位[3:0]
GE[3:0]使用一些SIMD指令
IT[7:2]if then条件执行Thumb-2指令组
E控制加载/存储字节序
A禁用abort模式
I禁用IRQ模式
F禁用FIQ模式
T显示核心是否处于Thumb状态
M[4:0]处理器模式:0x10~0x1F

*加粗的为KEIL关注的寄存器位。

CPSR寄存器M位与处理器模式:

M值模式
0x10User
0x11FIQ
0x13SVC
0x17Abort
0x1BUndef
0x1FSystem
0x16Monitor
0x12IRQ

异常向量表

异常向量表在程序起始位置的开始,以下所有地址皆为程序start为基点的偏移量。

地址HypaMonitorSecureNon-secure
0x00NO USENO USEResetNO USE
0x04UdefinedNO USEUndefined InstructionUndefined Instruction
0x08Hypervisor CallSecure Monitor CallSuperviesor CallSupervisor Call
0x0CPerfetch AbortPerfetch AbortPerfetch AbortPerfetch Abort
0x10Data AbortData AbortData AbortData Abort
0x14Hyp trapNO USENO USENO USE
0x18IRQIRQIRQIRQ
0x1CFIQFIQFIQFIQ

汇编示例:

.text
.global _start
_start:
@0
	b reset
@4
	b undef_handler
@8
	b swi_handler
	b perfetch_handler
	b databort_handler
	nop
	b irq_handler
	b fiq_handler
对于FIQ
  • FIQ有更多的独立寄存器(R8~R12),在存储现场压栈时压入内存的寄存器更少以此达到更快的中断。

  • FIQ在中断向量表的最末尾,FIQ操作的代码段则紧接这中断向量表,从而少跳转一次达到更快的中断效果。

  • 同时进入FIQ模式会禁止IRQ,拥有比IRQ更高的中断优先级,在FIQ结束前,IRQ不会被相应。

ARM指令

指令流水线

CPU执行一条指令分为三步,即:

  1. Fetch:读指令:从存储器读取指令

  2. Decode:译码:解码指令中用到的寄存器

  3. Exexute:执行:寄存器读(从寄存器Bank),移位及ALU操作,寄存器写(到寄存器Bank)

ARMThumbStep
PCPCFetch
PC-4PC-2Decode
PC-8PC-4Execute

为了提高CPU执行指令的效率,所以CPU在执行指令时是以流水线的方式进行的:

单元step1step2step3step4step5
Fetch单元指令1:Fetch指令2:Fetch指令3:Fetch
Decode单元指令1:Decode指令2:Decode指令3:Decode
Execute单元指令1:Execute指令2:Execute指令3:Execute

指令格式

<Mnemonic>{<cond>}{s} {Rd},{Rn},{shifter_operand}
原文解释
Mnemonic助记符
cond条件码
s当前指令执行会引起CPSR寄存器的NZCV位变化
Rd目标寄存器
Rn第一操作寄存器
shifter_operand第二操作数

注:比较指令没有目标寄存器,不加s修饰也会引起CPSR寄存器NZCV位变化。

ARM指令语句助记符

种类指令含义
数据传输指令MOVMOV Rd,Rn;将第一操作寄存器的数据移到目标寄存器Rd
MVNMVN Rd,Rn;将第一操作寄存器的数据取反后移到目标指令集Rd
比较指令CMPCMP Rd,Rn;减法比较Rd-Rn,更新CPSR
CMNCMN Rd,Rn;加法比较Rd+Rn,更新CPSR
TSTTST Rd,Rn;位测试Rd&Rn,更新CPSR
TEQTEQ Rd,Rn;相等测试Rd^Rn,更新CPSR
加法指令ADDADD Rd,Rn,shifted_opt;Rd=Rn+shifted_opt
ADCADC Rd,Rn,shifted_opt;Rd=Rn+Rn+C(CPSR);加法进位指令
减法指令SUBSUB Rd,Rn,shifted_opt;Rd=Rn-shifted_opt
SBCSUB Rd,Rn,shifted_opt;Rd=Rn-shifted_opt-C(CPSR);减法借位指令
RSBRSB Rd,Rn,shifted_opt;Rd=shifted_opt-Rn;反减
RSCRSB,Rd,Rn,shifted_opt;Rd=shifted_opt-Rn-C(CPSR);反减借位
位运算指令ANDAND Rd,Rn,shifted_opt;Rd=Rn&shifted_opt
ORRORR Rd,Rn,shifted_opt;Rd=Rn|shifted_opt
EOREOR Rd,Rn,shifted_opt;Rd=Rn^shifted_opt;相同为零不同为一
BICEOR Rd,Rn,shifted_opt;取二进制shifter_opt为1的位将Rn对应的位写零,结果导入到Rd
无符号乘法指令UMULLUMULL Rd_low,Rd_high,Rn,Rm;Rd_high:Rd_low=Rn*Rm
UMLALUMLAL Rd_low,Rd_high,Rn,Rm;Rd_high:Rd_low=Rn*Rm+Rd_high:Rd_low
条件码(conditional execution)
条件码助记符寄存器标识位条件含义
0000EQZ=1相等
0001NEZ=0不相等
0010CSC=1无符号数大于或等于
0011CCC=0无符号数小于
0100MIN=1负数
0101PLN=0正数或零
0110VSV=1溢出
0111VCV=0未溢出
1000HIC=1&&Z=1无符号数大于
1001LSC=0||Z=1无符号数小于或等于
1010GEN=V带符号数大于或等于
1011LTN!=V带符号数小于
1100GTZ=0&&N=V带符号数大于
1101LEZ=1||N!=V带符号数小于或等于
1110ALAnyAlways

跳转指令B配合条件码,可实现条件跳转的逻辑结构。

指令语句示例代码

MOV/MVN赋值指令

@transmit commmand
MOV R0,#1
MVN R0,#1

MOV将值赋给目标寄存器,MVN取反输入(因为是无符号数,所以0x-1回环为0xFFFFFFFF)。

CMP/CMN/TST/TEQ比较指令

MOV R0,#5
MOV R1,#3
CMP R0,R1      @ CPSR
SUBHI R0,R0,R1 @ R0<-(R0-R1)
SUBLS R1,R1,R0 

CMP比较后CPSR寄存器的C位由0置为1。

@compare command
MOV R0,#2
CMP R0,#2
CMP R0,#3

MOV R0,#2
CMN R0,#-2

MOV R0,#16
TST R0,#(1<<4)

MOV R0,#234
TEQ R0,#234

ADD加法运算/ADC进位加法运算

MOV R0,#0x1
MOV R1,#0xFFFFFFFF
MOV R2,#0x1
MOV R3,#0x1
ADDS R5,R3,R1
ADC R4,R0,R2   @进位
NOP
NOP
寄存器运行前第一步后第二步后第三步后第四步后第五步后第六步后
R00x000000000x00000001
R10x000000000xFFFFFFFF
R20x000000000x00000001
R30x000000000x00000001
R40x000000000x00000003
R50x000000000x00000000
指令CPSR
CMP减法比较小于(N置1),大于等于(C,Z置1)
CMN加法比较(与负数)
TST位比较(与位移量)C置1
TEQ相等测试

SUB减法运算/SBC借位减法运算

MOV R0,#0x2
MOV R1,#0x1
MOV R2,#0x1
MOV R3,#0xFFFFFFFF
SUB R5,R1,R3
SBC R4,R0,R2  @借位
NOP
NOP

R0&R1组成数1的高八位和低八位,R2&R3组成数二的高八位低八位。

R1-R3时借位,此时R0被借位后为0x00000001。

寄存器运行前第一步后第二步后第三步后第四步后第五步后第六步后
R00x000000000x00000002
R10x000000000x00000001
R20x000000000x00000001
R30x000000000xFFFFFFFF
R40x000000000x00000000
R50x000000000x00000002

RSB反减运算

因为受汇编格式第一第二操作数皆为寄存器而不能是常数的限制,所以出现常数为被减数,寄存器值为减数的情况时需要使用RSB指令。

MOV R1,#0x01
RSB R0,R1,#0xFF @反减

寄存器变化:

寄存器运行前运行后
R00x000000000x000000FE
R10x000000000x00000001

BIC按位清零/MSR寄存器给特殊寄存器赋值

MRS R0,CPSR
BIC R0,#0x3 @按位清零
MSR CPSR,R0
NOP
NOP

寄存器变化:

寄存器运行前第一步后第二步后第三步
R00x000000000x000000D30x000000D00x000000D0
CPSR0x000000D30x000000D30x000000D30x000000D0
模式状态SVCSVCSVCUSER

UMULL乘法运算/UMLAL乘法累加运算

MOV r2,#2
MOV R3,#0XFFFFFFFF
UMULL R0,R1,R2,R3
UMLAL R0,R1,R2,R3
NOP
NOP

寄存器变化

寄存器运行前第一步后第二步后第三步后第四步后
R20x000000000x00000002
R30x000000000xFFFFFFFF
R10x000000000x000000010x00000003
R00x000000000xFFFFFFFE0xFFFFFFFC

R1为高32位,R0位低32位。

UMULL:0xFFFFFFFF*2=0x1FFFFFFFE ;

UMLAL:Rd_high:Rd_low=Rn*Rm+Rd_high:Rd_low ;2*0xFFFFFFFF+0x1FFFFFFFE=0x3FFFFFFFC

B 跳转指令

	MOV R0,#0X1
	MOV R1,#0X2
	B MDADD
LOOP:
	B .
MDADD:
	ADD R2,R0,R1;
	MOV PC,LR

B MDADD可以使程序跳过LOOP部分,直接执行MDADD部分。MOV PC,LR使程序PC指针又指向程序起始位置。

ARM伪指令

指令语句有对应的机器码,伪指令没有对应的机器码。伪指令的格式与指令的格式相同。

伪指令因为可以操作内u才能空间,所以引入了两种特殊符号:

  1. =:=DATA,可以获取数据段的内存地址,类似C语言的&。
  2. []:[Register],可以获取寄存器存储的内存地址里所存储的数据,类似C语言的*。

同时引入.text代码段与.data数据段,数据段的数据存储在内存,数据格式更加灵活,且可以被更改。

伪指令助记符

种类指令含义
加载指令,可操作内存空间,使寄存器与内存数据交换LDRLDR Rd,Addr;将立即数/地址赋值给目标寄存器
LDRB以字节为单位加载数据
LDRH以半字为单位加载数据
存储指令,可操作内存空间,使寄存器与内存数据交换STRSTR Rd,=Addr 将Rd的数据存储到地址
STRB以字节为单位存储数据
STRH以半字为单位存储数据
加载指令,load from memory to registerLDMLDM Rd!,{Rm-Rn};意为将Rd所指地址的数据自增形式存储到Rm到Rn的寄存器里,Rd自增。
存储指令,store to memory from registerSTMSTM Rd!,{Rm-Rn};意为将Rm到Rn寄存器里的值由寄存器的低地址到高地址,以自增形式赋给Rd所指向的首地址空间,Rd自增。

*单位:字为4byte,即32bit,八位十六进制数;半字即为2byte,16bit;字节即1byte,8bit

伪指令于语句示例

LDR/STR
	LDR R9,=VAR1
	LDR R0,[R9]
	ADD R0,R0,#0X1
	STR R0,[R9]
	LDR R1,[R9]
	NOP
	NOP
.data @声明此处是数据段
	VAR1: .WORD 0X12345678 @声明整个VAR1存储在一个字里
  1. 将VAR1的地址存储在R9
  2. 取R9所存储的地址里数据赋给R0,R0变化为0x12345678
  3. R0加0x1变为0x12345679
  4. 将R0存储的数据0x12345679存储到R9存储的地址,也就是VAR1此时变为0x12345679,可在keil的Memory窗口查看内存变化
  5. 将R9所存储的地址里的数据赋给R1,R1变化为0x12345679
LDRB/STRB
	LDR R0,=ARR1
	LDR R2,=ARR2
COPY:
	LDRB R1,[R0],#1
	STRB R1,[R2],#1
	CMP R1,#0
	BNE COPY
	NOP
	NOP
.data
	ARR1: .STRING "1234567\0" @字符串"1234567\0"
	ARR2: .SPACE 8 @在内存申请一片8字节的空间
  1. 将ARR1的首地址存储在R0

  2. 将ARR2的首地址存储在R2

  3. 将R0存储的首地址里的数据赋给R1,存储单位为一个字节,之后R1值加1,即R1充当指针,指针向后一个字节

  4. 将R1的数据赋值给R2存储的首地址内存里,之后R2加1,即指针向后一个字节

  5. 比较R1与0,在此程序中,0意味着中止符“\0”

  6. 比较结果若不同,则重复COPY段的指令。

这样就可以将ARR1字符串赋给ARR2字符串。

LDMIA/STMIA/LDMIB/STMIB/LDMDA/STMDA/LDMDB/STMDB
  • IA:increment after;先操作,后增加;num++
  • IB:increment before;先增加,后操作;++num
  • DA:decrement after;先操作,后减少;num–
  • DB:decrement before;先减少;后操作;–num
	LDR R0,=ARR1
	LDR R1,=ARR2
	LDMIA R0!,{R3-R4}
	STMIA R1!,{R3-R4}
	NOP
	NOP
.data
	ARR1:.BYTE '1','2','3','4','5','6','7','8' @元素为一字节的ARR1
	ARR2: .SPACE 8
  1. 将ARR1的首地址存储在R0

  2. 将ARR2的首地址存储在R1

  3. 将R0首地址的数据赋给R3到R4,之后R0增加,即指针向后移动一个单位,以此类推直至R3-R4将ARR1全部数据存储。

  4. R3-R4的数据赋给R1存储的地址,即ARR2的首地址,之后R1增加,即指针向后移动一个单位,以此类推直至将R3-R4的全部数据存储到ARR2

这种操作可以在压栈出栈中使用,后文压栈出栈和软中断会进行详细分析。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值