ARM工作模式
1.用户模式:(USR:User)
用户模式是用户程序的工作模式,它运行在操作系统的用户态,它没有权限去操作其他硬件资源
只能执行处理自己的数据,也不能切换到其他模式下,要想访问硬件资源或切换到其他模式只能通过软中断或产生异常。
2.系统模式(SYS:System)
系统模式是特权模式,不受用户模式的限制
用户模式和系统模式公用一套寄存器
操作系统在该模式下可以方便的访问用户模式的寄存器,而且操作系统的一些特权任务可以使用这个模式访问一些受控的资源
3.中止模式(ABT:Abort)
中止模式用于支持虚拟内存或存储器保护
当用户程序访问非法地址,没有权限读取的内存地址时,会进入该模式
linux下编程经常会出现的segment fault 通畅都是在该模式下抛出返回的
4.未定义模式(UDF:Undifined)
未定义模式用于支持硬件协处理器的软件仿真
CPU在指令的译码阶段不能识别该指令操作时,会进入未定义模式
5.快速中断模式(FIQ:Fast Interrupt Request)
快速中断模式是相对一般中断模式而言的
它是用来处理对时间要求比较紧急的中断请求, 主要用于高速数据传输及通道处理中。
6.一般中断模式(IRQ:Interrupt Request)
一般中断模式也叫普通中断模式
注:
ARM系列有7个基本工作模式,Cortex-A系列有八种基本工作模式
除用户模式以外,其余的所有6种模式称之为非用户模式,或特权模式(Privileged Modes)
其中除去用户模式和系统模式以外的5种又称为异常模式(ExceptionModes), 常用于处理中断或异常,以及需要访问受保护的系统资源等情况。
寄存器
总结:
所有模式都共享的寄存器:R0-R7,R15,CPSR
除了FIQ模式其他模式共享:R8-R12,FIQ(R8-R12)
5种异常模式私有的寄存器:R13-R14,SPSR,USR/SYS(R13-R14)
MON模式次有的寄存器:SPSR,R13-R14
用途:
R0-R10:存放用户数据
R11:fp:frame-pointer ---------用来记录一个栈空间的开始地址
R12:ip:The Intra-Procedure-Call scratch register--------用来临时存储sp
R13:sp:stack pointer---------栈指针寄存器,每一种模式有自己的 r13,所以允许每一种异常都有自己的堆栈指针
R14: lr: link register------在发生跳转的时候,用来保存pc寄存器的值
每一种模式都有自己的r14
R15:pc:program counter--------用来存放CPU需要执行的指令所在的内存地址
通常用作程序计数器
在程序开始执行前,将程序指令序列的起始地址,即程序的第一条指令所在的 内存单元地址送入PC,CPU 按照 PC的指示从内存读取第一条指令。
当执行指令时,CPU自动地修改PC 的内容,即每执行一条指令PC增加一个 量,使 PC总是指向正在取指的指令地址
指令格式
(1)<opcode> {<cond>} {S} <Rd> ,<Rn>,<shift_operand>
其中<>号内是必须的,{}号内的项时可选的
(2)opcode-------- 指令助记符--------ADD表示加法运算
操作码。比如:加法、减法、乘法、除法等
(3)cond
条件:1.根据条件是否执行指令
2.条件码
原理:1.ARM系统中提供了一个专门的寄存器(程序程序寄存器)cpsr
2.记录当前CPU的运行状态,他的最高的四位会有一个相应的记录
3.条件码会去查询cpsr寄存器的最高四位是否满足条件。
数据传输指令:
MOV:
语法 :
MOV{<cond>}{S} <Rd>,<shifter_operand>----------Rd = shifter_operand
shifter_operand---------可以为立即数,寄存器,并且支持移位操作
立即数---------一般表示整数常常量
MOV目标寄存器,操作数2
功能:
将操作数2的值赋值给目标寄存器
EG:
MVN:
堆内存中的存储的值进行按位取反(~)
格式-----------MVN目标寄存器,操作数2
功能-----------将操作数2取反的值给目标寄存器
Eg:
LDR:
功能---------将任意数据加载到目标寄存器中
思考---------为什么不用MOV存放到寄存器中?
MOV能存放的只有合法立即数
LDR可以直接将任意数据加载到寄存器中
通过寄存器获得要访问的内存地址,在进行操作,一般只涉及一个数据操作
示例——LDR r0,=0x12345678
数据计算指令:
ADD:
功能--------加法指令
语法格式:
Eg:
ADD R0,R1,#2——R0 = R1 + 2
ADD R0,R1,R2——R0 = R1 + R2
ADD R0,R1,R2,LSL #3 —— R0 = R1 + R2 << 3
SUB:
功能:减法指令-------将操作数1减去操作数2的结果给目标寄存器
Eg:
MUL:
功能:乘法指令--------将操作数1乘以操作数2的结果放在目标寄存器里
合法立即数:
概念:在ARM指令中可以使用的立即数必须是合法的否则导致ARM指令执行异常
原因:ARM指令长度有限,不能都用于表示立即数,所以不能表示所有立即数,最终会导致部分立即数不能表示
合法立即数规则:
规则——所有的立即数必须要通过一个8位立即数通过偶数位获得 否则不合法
Eg:
判断立即数是否合法:
比较指令:
语法格式:
注意:
条件码:
跳转指令:
B: B{L}{<cond>} <target_address>
跳转到指定目标地址:1.目标地址可以使用标号进行表示
2.跳转到标签,标签就是目标地址
BL----格式------BL标签
功能------跳到一个指定标签,BL跳转之前,会将跳转前的PC的值保存到LR寄存器中
注意:
bl/b指令24位立即数用于表示跳转到目标地址,24位能够表示的范围为+/-8M,在进行左移动两位相当于+/-32M
将得到的值加到PC寄存器中,即得到跳转的目标地址。由这种计算方法可知,跳转的 范围大致为-32M~+32M
位运算:
AND
功能:按位与
语法格式:AND{<cond>} {S} <Rd>, <Rn>, <shifter_operand>
举例:AND R0, R1, #2
AND r0,r1,r2
AND R0, R1,R2,LSL #3
ORR
功能:按位或
语法格式:ORR{<cond>} {S} <Rd>, <Rn>, <shifter_opearand>
ORR目标寄存器,操作数1,操作数2
举例:ORR r0,r1,r2
ORR R0,R1,#2
ORR R0,R1,R2,LSL #3
EOR
功能:按位异或
语法格式:
举例:
BIC
功能:
位清除
将操作数1按位与操作数2取反的结果存放在目标寄存器
目标寄存器 = 操作数1 &~ 操作数2
语法格式:
示例:
练习:
寄存器间接寻址:
通过寄存器获得要访问的内存地址,在进行操作,一般只涉及一个数据的操作
中括号[ ]内的寄存器 表示该寄存器当中存了一个地址
LDR r0,[r1]------将r1寄存器中的值作为地址取出里面的值读到r0中
r0 = *r1
STR r0,[r1] -----将r0寄存器中的值写道r1存放的地址中
*r1 = r0
基址寻址模式:
栈操作指令:
出栈:LDMFD
ldm sp!,{registers(寄存器列表)}
进栈:STMFD
stm sp! ,{registers(寄存器列表)}
注意:
在对栈操作之前,必须设置sp的值
进栈和出栈的方式一样,ATPCS标准规定满减栈-------ATPCS是arm公司针对arm平台编译器的规范
栈的操作模式:
ARM 提供了专门用于操作 sp(r13) 的指令,用法与 stm/ldm 地址模式保持一致,在 arm 编程规范中,默认使用的是满递减模
满栈递增:
入栈是向高地址的方式移动,然后在存入数据
出栈是先拿出数据,然后向低地址方向移动
满栈递减:
入栈是向低地址的方式移动,然后再存入数据
出站是先拿出数据,然后向高地址方向移动
空栈递增:
入栈先存放数据,然后向高地址方向递增
出栈是先向低地址方向移动,然后再拿出数据
空栈递减:
入栈先存放数据,然后向低地址方向递增
出栈是先向高地址方向移动,然后在拿出数据
空栈与满栈:
四种浅模式:
CPSR/SPSR操作指令:
读操作:
MRS Rn , CPSR/SPSR
将状态寄存器的值,读到通用寄存器
什么时候用:
1.当需要改变程序状态寄存器的内容时,可用MRS将程序状态寄存器的内容读入到通用寄存器,修改后再写回程序状态寄存器
2.当在异常处理或线程切换时候,需要保存程序状态寄存器的值吗,可先用该指令独处程序状态寄存器的值,然后保存
指令示例:
a. MRS R0 , CPSR ; 传送CPSR的内容到R0
b. MRS R0 , CPSR ; 传送SPSR的内容到R0
写操作:
MSR CPSR/SPSR , RN
将通用寄存器的值,写到状态寄存器
指令示例:
a. MR CPSR,R0;传送R0的内容到CPSR
b. MR SPSR,R0;传送R0内容到SPSR
c. MSR CPSR_C , R0; 传送R0内容到SPSR,但仅仅修改CPSR中的控制位域低8位
ARM体系的流水线作业:
最佳流水线:
LDR流水线:
分支流水线:
中断流水线:
ATPCS标准:
概念:ATPCS即ARM-THUMB procedure call standard(ARM-Thumb过程调用标准)的简称
参数规则:函数参数传递的时候,前四个参数通过r0-r3来传递,超过四个的参数通过栈来传递
返回:值规则:函数返回值通过r0带回
栈模式规则:
main函数编译完后,就是个标签Label
分析步骤:
mov ip ,sp —— 把sp的值赋值给ip,ip是暂存sp的
stmfd sp!,{fp,ip,Ir,pc} —— 入栈操作,压入fp,ip,Ir,pc的值要减去四次
先放那个? fp还是pc? —— pc 要遵从大寄存器对大地址,小寄存器 对小地址
sub fp,ip,#4:
fp = ip - 4
fp是栈曾寄存器,记录的是栈的开始地址
fp是栈开始,sp是栈结束,相减就是栈空间大小
sub sp,sp,#16:
第一、二通过R0,R1传
str r0,[fp,#-24] —— argc
str r1,[fp,#-28] —— argv
mov r3,#0
mov r3 , [fp,#-20]
mov r3 , #0
mov r3,[fp,#-16]
sub sp,fp,#12
汇编调用c语言:
操作:
1.在原先文件中新建文件test.c(保存)
2.将文件加入项目中
3.将test.c中写入c语言代码
4.编译后查看
练习:
C程序中调用汇编:
格式:
输出列表:
输入列表:
修改列表:
注意:如果没有三个表可以空着为什么会有修改列表,因为编译器会翻译c语言使用到这些寄存器他要是用什么寄存器是知道的,突然内联之后,改变寄存器的值,就需要让编译器考虑进去 c变量的引用,从输出列表到输入列表开始编号:第一个C变量%0,第二个C变量%1,...
示例格式:
irq使能示例:
允许irq异常
使能irq异常,需要操作CPSR寄存器
使能irq异常示例:
修改列表中写入r0,r0是通用寄存器,内联汇编中也操作r0,对r0做更改,所以要通知编译器
为什么不写cpsr?
cpsr是特殊寄存器,cpsr不会被修改
练习:
无输出写法格式
volatile:
优化思想:
如果我们在前面已经将这个变量所对应的内存数据读到寄存器中,而我们再次需要读这个变量所在对应的内存的数据的时候,编译器前面我们已经再寄存器中存放过值了
为了提高效率,它回直接用上一次寄存器中的值,而不是从内存中的读值
优化级别:01—— 一级优化
02(speed)/Os(size)—— 二级优化
03 —— 三级