目录
1、接上一个csdn特殊功能寄存器
1.1CPSR寄存器
1.2SPSR寄存器
1.3CPSR寄存器的高四位和第四位 编辑
2、汇编指令的分类
3、汇编指令的基本格式
4、数据搬移指令(赋值指令)
4.1指令码
4.2指令格式
4.3测试代码
4.5立即数
4.6ldr伪指令
5、位移操作运算指令
5.1指令码
5.2指令格式
5.3测试代码
6.位运算操作指令
6.1指令码
6.2指令格式
6.3测试代码
6.4练习代码
7、算数运算指令
7.1指令码
7.2指令格式
7.3测试代码
1、接上一个csdn特殊功能寄存器
1.1CPSR寄存器
CPSR寄存器------the current program status register
CPSR寄存器的中文名是当前程序状态寄存器
CPSR寄存器的作用:用于保存当前程序的状态
1.2SPSR寄存器
SPSR寄存器-------the save program status register
SPSR寄存器的中文名字是备份程序状态寄存器
SPSR寄存器的作用:用于备份程序的状态
这张图展示了ARM处理器用户模式(USER)与中断请求模式(IRQ)之间的异常处理流程,核心是通过CPSR和SPSR寄存器实现模式切换与状态备份恢复,流程是1.先正常执行,此时处理器处于普通执行状态,使用用户模式的寄存器,CPSR寄存器记录当前程序的运行状态,2.触发异常用户代码执行中断事件,处理器会备份当前状态将CPSR寄存器的值保存到IRQ模式对应的SPSR中确保用户模式下不会丢失,3.开始处理异常代码,此时使用IRQ模式的寄存器组,独立于用户模式的寄存器,保证不会干扰用户代码的执行,4.从IRQ到USER模式异常处理完毕后处理器会从SPSR中备份的用户模式状态写会CPSR切换到USER模式继续执行后面的代码,
CPSR:记录当前模式下的程序状态(标志位、中断控制、处理器模式等),是实时状态的 “快照”。
SPSR:是异常模式(如 IRQ、FIQ)下的 “备份寄存器”,用于保存 ** 原模式(如 USER)** 的 CPSR 值,确保异常处理完成后能恢复原状态。
总结:这种机制保证了 ARM 处理器在处理异常时,既能及时响应中断,又能在处理完毕后准确回到原程序的执行上下文,是 ARM 架构 “多模式、高可靠性” 设计的核心体现。自我理解:可以这样理解触发异常事件是将CPSR中保存的值给SPSR,异常执行结束将SPSR中的值还原给CPSR回到user模式继续执行后面的代码
1.3CPSR寄存器的高四位和第四位

N【31】位:
负数标志位(用于比较两个数的大小)
当汇编指令的执行结果位负数时,N位会被硬件自动置为1;否则,清0;
Z【30】位:
零标志(用于比较两个数是否相等时)
当汇编指令的执行结果为0时,z位会被硬件自动置1否则;清0;C【29】位:
进位/借位标志位
当汇编指令的执行结果产生进位时,c位会被硬件自动置为1;否则清零(加法运算)
当汇编指令的执行结果产生借位时,C位会被硬件自动清零;否则置1(减法运算)
可以看后面的第八条
V【28】位:
溢出标志位/符号标志位
当汇编指令的执行结果对符号位产生变化时,v位会被硬件自动置1;否则,清零
I【7】位:
FRQ模式使能位/IRQ模式屏蔽位
I=1时,屏蔽IRQ模式(无法进入到IRQ模式下)
I=0时,不屏蔽FIQ模式(可以进入到FIQ模式下)
T【5】位:状态位/ARM状态屏蔽位
T=1时,屏蔽ARM状态(不适用ARM汇编指令集,默认使用Tumb汇编指令集)
T=0时,不屏蔽AMR状态(可以使用ARM汇编指令集)
M【4:0】位
模式位/工作模式位
CPSR寄存器的高四位由硬件控制,不需要认为更改
CPSR寄存器的第八位可以认为更改
M[4:0] -> 处理器模式
10000 -> User 模式
10001 -> FIQ 模式
10010 -> IRQ 模式
10011 -> Supervisor(SVC)模式
10110 -> Monitor(MON)模式
10111 -> Abort(ABT)模式
11010 -> Hyp(HYP)模式
11011 -> Undef(UND)模式
11111 -> System(SYS)模式
2、汇编指令的分类
基础汇编指令:
1、数据操作指令
1.1数据搬移指令(赋值指令=)
1.2移位运算指令(<<,>>)
1.3位运算指令(&,|,~,^)
1.4算术运算指令(+,-,*,/)
1.5比较指令(<,>,==,!=)
2、跳转指令
进阶汇编指令:
3、单寄存器内存读写指令
4、栈指针寄存器内存读写指令(包含了多寄存器内存读写指令)
5、CPSR特殊功能寄存器内存读写指令
6、swi软中断指令
3、汇编指令的基本格式
{opcode}{cond}{s} Rd,Rn, oprand_shifter2|
| | | | | |----------------->第二操作数(相当于右操作数)
| | | | | |----------------->第二操作数可以是:
| | | | | | 1、立即数
| | | | | | 2、普通寄存器
| | | | | | 3、经过移位的寄存器
| | | | |
| | | | |------------------第一操作寄存器(相当于左操作数)
| | | |------------目标寄存器,用于存放当前汇编指令的执行结果
| | |
| | |----------状态位,+s,当前汇编指令的执行结果会影响xpsr寄存器的nzcv位
| | 不+s,当前汇编指令的执行结果不会影响cpsr寄存器的nzcv位
| |----------条件码,用于让汇编指令的指令(在使用比较指令时会使用)
|
|----------------指令码,也就是汇编指令的名字
注意:
1、{opcode}{cond}{s}指令码、条件码,状态位连在一起写的,不允许出现空格
2、Rd,Rn,oprand_shifter2目标寄存器、第一操作寄存器、第二操作数连在一起写、但是需要使用逗号隔开
3、{opcode}{cond}{s} 和 Rd,Rn,oprand_shifter2 这两个部分中间需要用空格隔开
4、汇编指令指令么有以;结尾,所以一条汇编指令写一行
5、汇编指令没有大小写区分
mov r0,#0xff ==== MOV R0,#0xFF ====MoV r0,#0xFF这三句是一样的
6、在当前汇编文件中,使用的汇编器支持的注释方式:
6.1单行注释@(不同的编译器支持的注释方式不同,可能有;,#......)
6.2多行注释
/**/
.if 0/1 .else .endif
4、数据搬移指令(赋值指令)
4.1指令码
mov -------- 直接赋值指令
mvn ------ 按位取反后赋值
4.2指令格式
mov/mvn Rd,operand_shifter2
赋值指令时没有第一操作寄存器的,只有目标寄存器和第二操作数
4.3测试代码
.text
.global _start
_start:
mov r0,#oxff @解释:将0xff赋值到R0寄存器中
@如果使用赋值指令时,第二个操作数是一个立即数
@需要在他的前面加上#
mvn r1,#0xff @解释:将0xff全部按位取反后,赋值给r1寄存器
@r1=~(0xff)=0xffffff00
mov r2,#(-0xff) @-0xff(存储的补码,正数源码和补码是一致的,负责需要计算)
@源码:0x800000ff
@反码:0xffffff00
@补码:0xffffff01
stop:
b stop
.end
4.5立即数
以mov这条汇编指令为例,不同的汇编指令的立即数是不一样的
以mov r0, #0xff为例,一条汇编指令占四个字节的空间
立即数是指可以被指令直接编码、无需从内存或者寄存器读取的常数。它的核心特点是“能被指令格式直接表示“。
立即数的判断步骤:
1、确定带判断数a;
2、在0x00~0xff范围内找一个数b;
3、将b循环右移偶数位(0、2、4......30位),若结果等于a,则是立即数
eg:
0xff是否为立即数
在0x00~0xff中找到b=0xff;
将b循环右移32位(等价于右移0位,因为32是偶数),结果仍为0xff,因此0xff是立即数
0xfff是否是立即数
在0x00~0xff中找不到任何数循环右移等于0xfff的,所以0xfff不是立即数
有效数:如果一个数全部按位取反后,能够得到一个立即数,这个数就是一个有效数
有效数可以当做立即数使用
4.6ldr伪指令
ldr伪指令可以实现0x00000000~0xffffffff之间任意数的赋值操作
指令格式:ldr Rd,=任意数
如果以后遇到一个数,不知道是否是立即数,可以直接使用ldr进行赋值操作
eg:
ldr r0,=0x12345678
5、位移操作运算指令
5.1指令码
lsl-------逻辑左移/无符号位 ------ 高位移出,低位补0
lsr------- 逻辑右移/无符号数右移 ------低位移出,高位补0ror ------ 循环右移 ------ 低位移出,补到高位
asr ----- 算数右移/有符号数右移 ----低位移出,高位补符号位
5.2指令格式
lsl/lsr/ror/asr Rd, Rn, oprand_shifter2
5.3测试代码
/***********************2、移位运算指令**************************/ /*
mov r0, #0xff
lsl r1, r0, #8 @ 将r0寄存器中的值逻辑左移8位后赋值给r1寄存器
@ r1 = r0 << 8 = 0xff00
lsr r2, r1, #12 @ 将r1寄存器中的值逻辑右移12位后赋值给r2寄存器
@ r2 = r1 >> 12 = 0xf
ror r3, r2, #4 @ 将r2寄存器中的值循环右移4位后赋值给r3寄存器
@ r3 = 0xf0000000
asr r4, r3, #4 @ 将r3寄存器中的值算术右移4位后赋值给r4寄存器
@ r4 = 0xff
@ 高位补符号位指的是所有高位都需要补符号位,而不是只有最高位补符号位
*/ /***********************2、第二操作数的所有情况**************************/
@ 第二操作数可以是一个立即数
mov r0, #0xff @ 解释:将0xff赋值给r0寄存器中
@ 第二操作数可以是一个普通寄存器
mov r1, r0 @ 解释:将r0寄存器中的值赋值给r1寄存器中
@ 第二操作数可以是一个经过移位的寄存器
mov r2, r1, lsl #4 @ 解释:将r1寄存器中的值逻辑左移4位后赋值给r2寄存器
@ 上述汇编指令的作用和这条lsl r2, r1, #4汇编指令的作用是一致的
6.位运算操作指令
6.1指令码
and --- 按位与(&)
orr --- 按位或(|)
eor --- 按位异或(^)mvn --- 按位取反(~)
口诀:
与0清0,与1不变
或1置1,或0不变
异或1取反,异或0不变
6.2指令格式
and/orr/eor/mvn Rd, Rn, oprand_shifter2
6.3测试代码
/***********************4、位运算操作指令**************************/
@ 32位数:
@ 31 0 @ **** **** **** **** **** **** **** ****
mov r0, #0xff
@ 目的:将r0寄存器中的第[3]位清0,其他位不变,最后赋值给r0寄存器
@ c语言写法:r0 = r0 & (~(0x1 << 3))
and r0, r0, #(~(0x1 << 3)) @ r0 = 0xf7
@ 目的:将r0寄存器中的第[3]位置1,其他位不变,最后赋值给r0寄存器
orr r0, r0, #(0x1 << 3)
6.4练习代码
@假设你不知道r0寄存器中的值
ldr r0, =0x12345678
@ 31 0
@ **** **** **** **** **** **** **** ****
@ 1> 将r0寄存器的第[3]位清0,保持其他位不变
and r0, r0, #(~(0x1 << 3))
@ 2> 将r0寄存器的第[29]位置1,保持其他位不变
orr r0, r0, #(0x1 << 29)
@ 3> 将r0寄存器的第[7:4]位清0,保持其他位不变
and r0, r0, #(~(0xf << 4))
@ and r0, r0, #(~(0b1111 << 4))
@ 4> 将r0寄存器的第[15:8]位置1,保持其他位不变
orr r0, r0, #(0xff << 8) @ orr r0, r0, #(0x0000ff00)
@ 5> 将r0寄存器的第[3:0]位按位取反,保持其他位不变
eor r0, r0, #(0xf << 0)
@ 6> 将r0寄存器的第[11:4]位修改为10101011,保持其他位不变
@ 推荐使用先清0再置1
and r0, r0, #(~(0xff << 4))
orr r0, r0, #(0b10101011 << 4) @ orr r0, r0, #(0xab << 4)
@ 也可以先置1再清0
orr r0, r0, #(0xab << 4)
and r0, r0, #(~(0x54 << 4))
7、算数运算指令
7.1指令码
add -----基础加法指令(不涉及CPSR寄存器中的c位的使用)
adc-------进阶加法指令(涉及CPSR寄存器中的c位使用)
sub--------基础减法指令(不涉及CPSR寄存器中的c位的使用)
sbc------进阶减法指令(涉及CPSR寄存器中的c位使用)
mul-------- 乘法指令
div-------除法指令(使用除法指令需要架构ARM-V8架构之上)
7.2指令格式
add/adc/sub/abc/mul/div Rd,Rn,oprand_shifter2
7.3测试代码
mov r1, #0x1
mov r2, #0x3
add r3, r1, r2 @r3=0x1+0x3=0x4
sub r4, r2, r1 @r4=0x3-0x1=0x2
@模拟两个64位数相减
@r1寄存器存放第一个64位数的高32位,r2寄存器存放第一个64位数的低32位
@r3寄存器存放第二个64位数的高32位,r4寄存器存放第二个64位数的低32位
@r5寄存器中存放相减后的高32位数,r6寄存器存放相减后的低32位数
mov r1, #0x5
mov r2, #0x2
mov r3, #0x1
mov r4, #0x8
@先低位相减
subs r6, r2, r4 @此时需要使用到s状态位
@由于当前指令的执行结果产生了借位
@并且高32位运算时,需要用到产生借位后的c位
@r6=r2-r4=0x2-0x8=0x2-0x2-0x6=0x0-0x6=0x0-0x1-0x5
@=0xffffffff-0x5=0xfffffffa
注:-1 mod 2³² = 2³² - 1 = 0xffffffff
(因为0xffffffff + 1 = 0x100000000
,对 2³² 取模后等于 0)。同样也可以这样理解当你10-1的时候是不是等于九是不是个位数里面最大的数同理当你0x0-0x1时也是一样的等于最大值0xffffffff
sbc r5, r1, r3 此时需要使用到sbc
由于此处高32位相减时,需要使用到产生借位后的位
r5= r1- r3- C位(注:无论是进位还是借位的c位都是0x1)
r5=r1-r3-c位=0x5-0x1-0x1=0x3
注意:不管C位存放的是0/1
只要c位产生了借位,就需要多减一个0x1
只要c位产生了进位,就要多加一个0x1
注:为什么加s,subs中的s是为了强制更新 CPSR 的借位标志(C 位),让后续的高位运算能正确处理低 32 位产生的借位,当指令后加s
(即 “set flags”)时,会在执行运算后自动更新 CPSR 的关键标志位(N、Z、C、V 等),其中:C 位(进位 / 借位标志):对于减法,C=0
表示有借位,C=1
表示无借位,这是 64 位减法中处理高位运算的核心依据。
@模拟两个64位数相加
@r1寄存器存放第一个64位数的高32位,r2寄存器存放第一个64位数的低32位
@r3寄存器存放第二个64位数的高32位,r4寄存器存放第二个64位数的低32位
@r5寄存器中存放相加后的高32位数,r6寄存器存放相加后的低32位数
mov r1, #0x1mov r2, #0xfffffffe
mov r3, #0x2
mov r4, #0x4
adds r6, r2, r4 r6=0xfffffffe+0x4=0xfffffffe+0x1+0x3=0xfffffffff+0x3
=oxffffffff+0x1+0x2=0x0+0x2=0x2
注:可以这样理解当9+1的时候是不是等于十是不是十位数里面最小的数同理当你0xffffffff+0x1时也是一样的等于0x0
adc r5, r1, r3 r5=r1+r3+c位=0x1+0x2+0x1=0x4
注:为什么加c位是因为发生了进位上面已经解释了。