一、温故知新
1、Uboot的操作
1)Uboot的简介
需要确定一点,系统上电后,Uboot是第一个执行的系统软件。
类似PC机上的BIOS(Basic Input Output System)
Uboot的核心功能:
【1】负责初始化硬件
【2】负责加载引导操作系统的启动
2)Uboot的初始化
Uboot的大部分代码都是C语言写的,但是开头的一部分代码是使用汇编写的,由于刚上电之后,内存还没有被初始化,所以C语言代码没有办法执行,(C语言的运行必须要有内存)所以,我们应该使用汇编语言对CPU、缓存、以及其他的硬件进行初始化。
2、ARM体系结构与编程
1)ARM指令集
大多数ARM核心都可以使用两种指令集:
【1】ARM指令集 32bit
【2】Thumb指令集 16bit
2)ARM支持的数据类型
arm支持的CPU字长
Byte 8bit
Halfword 16bit(2bytes)
Word 32bit(4bytes)
Doubleword 64bit(8bytes)
3)ARM的流水线
最经典的就是三级流水线
ARM汇编是一条指令,CPU在处理这个指令的时候,需要有三个步骤
【1】取指
【2】解码
【3】执行
三级流水线更适用于ADD SUB指令
五级流水线
【1】取指
【2】译码
【3】执行
【4】缓冲
【5】回写
五级流水线更适用于LDR指令
------------------------------------------------------------
CPU的整体性能会不会随着流水线级数的增加而增加?
答:不会,这需要考虑CPI(CPU的指令周期)是否会变小,CPI越小,CPU效率越高
------------------------------------------------------------
4)通用寄存器和特殊功能寄存器
通用寄存器:CPU内部的寄存器(用于管理CPU)32bit
特殊功能寄存器:外设中的寄存器(用于管理外设)32bit
5)ARM的工作模式
ARM有7种工作模式:
【1】SVC(管理模式)
【2】FIQ(快速中断模式)
【3】IRQ(中断模式)
【4】UNDEF(未定义模式)
【5】ABORT(中止模式)
【6】SYSTEM(系统模式)
【7】USER(用户模式)
6)异常 / 非异常模式区分
前五种属于异常模式
后两种属于非异常模式
7)特权 / 非特权模式区分
前六种属于特权模式
后一种属于非特权模式
8)ARM的工作状态
ARM有两种工作状态:
【1】ARM工作状态(当执行ARM指令时)
【2】Thumb工作状态(当执行Thumb指令时)
9)ARM的通用寄存器的内部结构
【1】组织结构
37个32bit的通用寄存器
[1]、31个通用寄存器
[2]、6个状态寄存器
[a]、1个CPSR(当前程序状态寄存器)
[b]、5个SPSR(程序状态存储寄存器)
【2】CPSR / SPSR寄存器
CPSR和SPSR的内部组织结构是一样的
bit31 | N | 判断结果是否为负 |
bit30 | Z | 判断结果是否为零 |
bit29 | C | 判断是否进位、借位、移位 |
bit28 | V | 判断是否符号位溢出 |
bit27 | Q | 是否支持DSP(数字信号处理)指令 |
bit26~25 | Reserved | 保留 |
bit24 | J | 有关Java编程模型 |
bit23~20 | Reserved | 保留 |
bit19~16 | 是否支持一条指令处理多个寄存器 | |
bit15~10 | Reserved | 保留 |
bit9 | E | 端序,标志大端小端 |
bit8 | A | 是否屏蔽ABORT |
bit7 | I | 是否屏蔽IRQ |
bit6 | F | 是否屏蔽FIQ |
bit5 | T | 工作状态 |
bit4~0 | Mode | 工作模式 |
【3】通用寄存器
不分组寄存器R0~R7
分组寄存器R8~R14
R13寄存器 SP(STACK POINTER)
R14寄存器 LR(LINK REGISTER)
R15寄存器 PC(PROGRAM COUNTER)
a)异常向量表
【1】异常类型
复位、未定义指令、软件中断、指令预取终止、数据中止、IRQ、FIQ
【2】当异常发生时
[1]、把CPSR寄存器中的内容复制到SPSR
[2]、把CPSR寄存器中的bit位设置合适的值
切换到ARM状态
切换到异常模式
屏蔽中断
[3]、把返回的地址存储到LR寄存器
[4]、设置PC为相应异常的入口地址
【3】从异常返回
[1]、把SPSR寄存器中的内容复制到CPSR
[2]、把LR寄存器中存储的返回值地址复制到PC
b)中断
中断是CPU感知外部事件的方法
中断一定是由硬件产生的
中断分为三级:
【1】中断源级:可以产生中断信号并且连接到了中断控制器上
【2】中断控制器级:GIC,可以屏蔽中断源上的中断信号
[1]、分配中断号
[2]、处理优先级
[3]、选择哪个CPU核分发中断信号
【3】ARM核级
[1]、保护现场(SPSR = CPSR)
[2]、将CPSR的值设置为FIQ或IRQ模式下的值
[3]、将函数的返回值保存到LR
[4]、放心大胆的跳转到异常向量的入口点执行
二、ARM汇编指令
ARM汇编指令又叫做助记符语言
在ARM汇编中注释用@(编译器架构不一样,注释所用符号不一样,视情况而定)
1、条件助记符
CPSR寄存器的高4位 | ||
bit31 | N(负号标志位) | 如果数据处理指令的结果为负,则N=1 如果数据处理指令的结果为非负,则N=0 |
bit30 | Z(0标志位) | 如果数据处理指令的结果为0,则Z=1 如果数据处理指令的结果为非0,则Z=0 |
bit29 | C(进位 / 借位 / 移位) | 对于加法指令,如果产生进位,则C=1,否则C=0 对于减法指令,如果产生借位,则C=0,否则C=1 对于有移位操作的非加减法指令,C为移位操作中最后移出的值 对于其他指令,C通常不变 |
bit28 | V(溢出标志位) | 正数 + 正数 = 负数,溢出,V=1 负数 + 负数 = 正数,溢出,V=1 正数 + 负数 ,不会溢出,V=0 |
常见的条件码 | ||
GE(1010) | 有符号的大于或等于 | N == V |
GT(1100) | 有符号的大于 | Z == 0 && N == V |
LE(1101) | 有符号的小于或等于 | Z == 1 && N != V |
LT(1011) | 有符号的小于 | N != V |
EQ(0000) | 相等 | Z == 1 |
NE(0001) | 不想等 | Z == 0 |
2、ARM的跳转指令
ARM指令的跳转:
【1】发生异常
【2】使用跳转指令
【3】直接向PC赋值
1)跳转指令 B、BL(Branch(树枝))
编码格式:
语法格式:
B{L} {<cond>} <target_address>
L:决定是否保存返回地址。
当有L时,当前PC寄存器的值将保存到LR寄存器中,然后执行跳转
当无L时,指令仅执行跳转,当前PC寄存器的值不会保存到LR寄存器中
<cond>:指令执行的条件码。(可选)
指令执行前,先对条件码进行判断,如果满足条件则执行该条指令,否则不执行
对条件码的判断是根据该指令的上一条指令执行后的CPSR寄存器中的前4位状态进行判断的
<target_address>:指令跳转的目标地址。
目标地址的计算方法:将指令中的24位带符号的补码立即数扩展为32位(扩展其符号位);将此32位数左移两位;将得到的值加到PC寄存器中,即得到跳转的目标地址。
跳转的范围大致为:±32MB
注意:
b . @相当于C语言的while(1);
2)带状态切换的跳转指令 BX
编码格式:
语法格式:
BX{<cond>} <Rm>
<cond>:指令执行的条件码。(可选)
当<cond>忽略时,指令为无条件执行
<Rm>:该寄存器中为跳转的目标地址。
当<Rm>寄存器的bit[0]为0时,目标地址处的指令为ARM指令;
当<Rm>寄存器的bit[0]为1时,目标地址处的指令为Thumb指令;
跳转地址限制:跳转的是绝对地址(我们刚才说的B / BL都是跳相对地址<相对于PC>)
3)ADR指令 (伪指令)
语法格式:
ADR{<cond>} register,expr
<cond>:指令执行的条件码。(可选)
register:目标寄存器。
expr:基于PC或者寄存器的地址表达式。
①当地址值不是字对齐的,其取值范围为 -255 ~ 255
②当地址值是字对齐的,其取值范围为 -1020 ~ 1020
使用说明:
①在汇编程序处理源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或者SUB指令来实现该伪指令的功能。
②如果不能用一条指令来实现ADR伪指令的功能,编译器将报错,因为ADR伪指令中的地址基于PC或者基于寄存器的,所以ADR读取到的地址为位置无关的地址。当ADR伪指令中的地址是基于PC时,该地址与ADR伪指令必须在同一代码段中
4)LDR指令 (伪指令)
语法格式:
LDR{<cond>} register,={expr | label -expr}
<cond>:指令执行的条件码。(可选)
register:目标寄存器。
expr:32位的常量。
编译器将根据expr的取值情况,决定如果处理LDR指令
①当expr表示的地址值没有超过MOV或MVN指令中的地址取值范围时,编译器用适当的MOV或MVN指令翻译LDR 指令
②当expr表示的地址值超过了MOV或者MVN指令中的地址取值范围时,编译器将该常数放在数据缓冲区中,同时用一条基于PC的LDR指令读取该常数
label -expr:基于PC的地址表达式或者是外部表达式。
①当label -expr为基于PC的地址表达式时,编译器将label -expr表示的数值放在数据缓冲区中,同时用一条基于PC的LDR指令读取该数值
②当label -expr为外部表达式,或者非当前段的表达式时,汇编编译器将在目标文件中插入连接重定位伪操作,这样链接器将在链接时生成该地址
使用说明:
①当需要读取到寄存器中的数据超过了MOV或MVN指令可以操作的范围时,可以使用LDR伪指令将数据读取到该寄存器中
②将一个基于PC的地址值或者外部的地址值读取到寄存器中。由于这种地址是在链接时确定的,所以这种代码不是位置无关的。
同时LDR伪指令处的PC值到缓冲区中的目标数据所在的地址的偏移量要小于4KB
3、ARM的数据处理指令
1)分类
【1】数据传送指令 MOV、MVN
【2】算数运算指令 ADD、ADC、SUB、SBC、RSB、RSC
【3】位运算指令 AND、ORR、EOR、BIC
【4】比较指令 CMP、TST、TEQ
2)格式
<opcode>{<cond>}{S} <Rd>,<Rn>,{shifter_operand}
注释:
<>是必须的,{}是可选的
<opcode>:汇编指令
<cond>:条件码
<Rd>:左值寄存器
<Rn>:右值寄存器
shifter_operand:第二个参数
3)shifter_operand的使用形式
-------------------------------------------------------------------------------------------
移位操作:
LSL | 逻辑左移 | 空位补零 |
LSR | 逻辑右移 | 空位补零 |
ASR | 算术右移 | 最高位补符号位 |
ROR | 循环右移 | 被移出的位重新插入到最高位 |
RRX | 带扩展位的循环右移 | 新的最高位由CPSR寄存器中的C位补充 |
-------------------------------------------------------------------------------------------
4)数据转送指令 MOV、MVN
指令介绍:
MOV指令将<shifter_operand>表示的数据传送到目标寄存器<Rd>中,并根据操作的结果更新CPSR中相应的条件标志位。
编码格式:
语法格式:
MOV{<cond>}{S} <Rd>, <shifter_operand>}
<cond>:指令执行的条件码。(可选)
当<cond>忽略时,指令为无条件执行
S:决定指令的操作是否影响CPSR中条件标志位的值。(可选)
当没有S时指令不更新CPSR中条件标志位的值。
当有S时指令更新CPSR中条件标志位的值;
①目标寄存器<Rd>为R15,则当前处理器模式对应的SPSR的值被复制到CPSR寄存器中,对于用户模式和系统模式,由于没有相应的SPSR,指令执行的结果将不可预料。
②目标寄存器<Rd>不是R15,指令根据传送的数值设置CPSR中的N位和Z位,并根据移位器的进位值carryout设置CPSR的C位,CPSR中的其他位不受影响。
<Rd>:目标寄存器
<shifter_operand>:向目标寄存器传送的数据。
适用范围有
[1]立即数、 mov r0, #0x10 r0 = 0x10
[2]寄存器、 mov r0, r1 r0 = r1
[3]寄存器 + 移位 mov r0, r1, lsl #2 r0 = r1 << 2
指令介绍:
MVN指令将<shifter_operand>表示的数据的反码传送到目标寄存器<Rd>中,并根据操作的结果更新CPSR中相应的条件标志位。
编码格式:
语法格式:
MVN{<cond>}{S} <Rd>, <shifter_operand>}
<cond>:指令执行的条件码。(可选)
当<cond>忽略时,指令为无条件执行
S:决定指令的操作是否影响CPSR中条件标志位的值。(可选)
当没有S时指令不更新CPSR中条件标志位的值。
当有S时指令更新CPSR中条件标志位的值;
①目标寄存器<Rd>为R15,则当前处理器模式对应的SPSR的值被复制到CPSR寄存器中,对于用户模式和系统模式,由于没有相应的SPSR,指令执行的结果将不可预料。
②目标寄存器<Rd>不是R15,指令根据传送的数值设置CPSR中的N位和Z位,并根据移位器的进位值carryout设置CPSR的C位,CPSR中的其他位不受影响。
<Rd>:目标寄存器
<shifter_operand>:向目标寄存器传送的数据。
适用范围有
[1]立即数、 mvn r0, #0xffffff00 r0 = 0x000000ff
[2]寄存器、 mvn r0, r0 r0 = ~r0
[3]寄存器 + 移位 mvn r0, r1, lsl #2 r0 = ~r1 << 2
5)算术运算指令 ADD、ADC、SUB、SBC、RSB
指令介绍:
ADD指令将<shifter_operand>表示的数据与寄存器<Rn>中的值相加,并把结果保存到目标寄存器<Rd>中,同时根据操作的结果更新CPSR中相应的条件标志位。
编码格式:
语法格式:
ADD{<cond>}{S} <Rd>, <Rn>, <shifter_operand>}
<cond>:指令执行的条件码。(可选)
当<cond>忽略时,指令为无条件执行
S:决定指令的操作是否影响CPSR中条件标志位的值。(可选)
当没有S时指令不更新CPSR中条件标志位的值。
当有S时指令更新CPSR中条件标志位的值;
①目标寄存器<Rd>为R15,则当前处理器模式对应的SPSR的值被复制到CPSR寄存器中,对于用户模式和系统模式,由于没有相应的SPSR,指令执行的结果将不可预料。
②目标寄存器<Rd>不是R15,指令根据传送的数值设置CPSR中的N位和Z位,并根据移位器的进位值carryout设置CPSR的C位,CPSR中的其他位不受影响。
<Rd>:目标寄存器
<Rn>:寄存器,为第一个源操作数所在的寄存器
<shifter_operand>:为第二个操作数。
适用范围有
[1]立即数、 add r0, r1, #0x10 r0 = r1 + 0x10
[2]寄存器、 add r0, r1, r2 r0 = r1 + r2
[3]寄存器 + 移位 add r0, r1, r2, lsl #2 r0 = r1 + r2 << 2
指令介绍:
ADC指令将<shifter_operand>表示的数据与寄存器<Rn>中的值相加,再加上CPSR中的C条件标志位的值,并把结果保存到目标寄存器<Rd>中,同时根据操作的结果更新CPSR中相应的条件标志位。
编码格式:
语法格式:
ADC{<cond>}{S} <Rd>, <Rn>, <shifter_operand>}
<cond>:指令执行的条件码。(可选)
当<cond>忽略时,指令为无条件执行
S:决定指令的操作是否影响CPSR中条件标志位的值。(可选)
当没有S时指令不更新CPSR中条件标志位的值。
当有S时指令更新CPSR中条件标志位的值;
①目标寄存器<Rd>为R15,则当前处理器模式对应的SPSR的值被复制到CPSR寄存器中,对于用户模式和系统模式,由于没有相应的SPSR,指令执行的结果将不可预料。
②目标寄存器<Rd>不是R15,指令根据传送的数值设置CPSR中的N位和Z位,并根据移位器的进位值carryout设置CPSR的C位,CPSR中的其他位不受影响。
<Rd>:目标寄存器
<Rn>:寄存器,为第一个源操作数所在的寄存器
<shifter_operand>:为第二个操作数。
适用范围,当我们的寄存器都是32bit的,但想要做64bit的加法运算,怎么处理?
这时,我们就可以使用add与adc组合
高32bit 低32bit 被加数 r0 r1 加数 r2 r3 和 r0 + r2 r1 + r3 adds r1, r1, r3 r1 = r1 + r3
adc r0, r0, r2 r0 = r0 + r2
这样寄存器r0中存储的就是正确结果的高32bit的值
指令介绍:
SUB指令从寄存器<Rn>中减去<shifter_operand>表示的数值,并把结果保存到目标寄存器<Rd>中,同时根据操作的结果更新CPSR中相应的条件标志位。
编码格式:
语法格式:
SUB{<cond>}{S} <Rd>, <Rn>, <shifter_operand>}
<cond>:指令执行的条件码。(可选)
当<cond>忽略时,指令为无条件执行
S:决定指令的操作是否影响CPSR中条件标志位的值。(可选)
当没有S时指令不更新CPSR中条件标志位的值。
当有S时指令更新CPSR中条件标志位的值;
①目标寄存器<Rd>为R15,则当前处理器模式对应的SPSR的值被复制到CPSR寄存器中,对于用户模式和系统模式,由于没有相应的SPSR,指令执行的结果将不可预料。
②目标寄存器<Rd>不是R15,指令根据传送的数值设置CPSR中的N位和Z位,并根据移位器的进位值carryout设置CPSR的C位,CPSR中的其他位不受影响。
<Rd>:目标寄存器
<Rn>:寄存器,为第一个源操作数所在的寄存器
<shifter_operand>:为第二个操作数。
适用范围有
[1]立即数、 sub r0, r1, #0x10 r0 = r1 - 0x10
[2]寄存器、 sub r0, r1, r2 r0 = r1 - r2
[3]寄存器 + 移位 sub r0, r1, r2, lsl #2 r0 = r1 - r2 << 2
注意:对于减法,如果产生借位,则C设置为0,否则设置为1
指令介绍:
SBC指令从寄存器<Rn>中减去<shifter_operand>表示的数值,再减去寄存器CPSR中C条件标志位的反码,并把结果保存到目标寄存器<Rd>中,同时根据操作的结果更新CPSR中相应的条件标志位。
编码格式:
语法格式:
SBC{<cond>}{S} <Rd>, <Rn>, <shifter_operand>}
<cond>:指令执行的条件码。(可选)
当<cond>忽略时,指令为无条件执行
S:决定指令的操作是否影响CPSR中条件标志位的值。(可选)
当没有S时指令不更新CPSR中条件标志位的值。
当有S时指令更新CPSR中条件标志位的值;
①目标寄存器<Rd>为R15,则当前处理器模式对应的SPSR的值被复制到CPSR寄存器中,对于用户模式和系统模式,由于没有相应的SPSR,指令执行的结果将不可预料。
②目标寄存器<Rd>不是R15,指令根据传送的数值设置CPSR中的N位和Z位,并根据移位器的进位值carryout设置CPSR的C位,CPSR中的其他位不受影响。
<Rd>:目标寄存器
<Rn>:寄存器,为第一个源操作数所在的寄存器
<shifter_operand>:为第二个操作数。
适用范围,当我们的寄存器都是32bit的,但想要做64bit的减法运算,怎么处理?
这时,我们就可以使用add与adc组合
高32bit 低32bit 被减数 r0 r1 减数 r2 r3 差 r4 r5 subs r5, r1, r3 r5 = r1 - r3(如果r1>r3,C=1否则C=0)
sbc r4, r0, r2 r0 = r0 - r2 - NOT(C)
这样寄存器r4中存储的就是正确结果的高32bit的值
指令介绍:
RSB指令从<shifter_operand>表示的数值中减去寄存器<Rn>值,并把结果保存到目标寄存器<Rd>中,同时根据操作的结果更新CPSR中相应的条件标志位。
编码格式:
语法格式:
RSB{<cond>}{S} <Rd>, <Rn>, <shifter_operand>}
<cond>:指令执行的条件码。(可选)
当<cond>忽略时,指令为无条件执行
S:决定指令的操作是否影响CPSR中条件标志位的值。(可选)
当没有S时指令不更新CPSR中条件标志位的值。
当有S时指令更新CPSR中条件标志位的值;
①目标寄存器<Rd>为R15,则当前处理器模式对应的SPSR的值被复制到CPSR寄存器中,对于用户模式和系统模式,由于没有相应的SPSR,指令执行的结果将不可预料。
②目标寄存器<Rd>不是R15,指令根据传送的数值设置CPSR中的N位和Z位,并根据移位器的进位值carryout设置CPSR的C位,CPSR中的其他位不受影响。
<Rd>:目标寄存器
<Rn>:寄存器,为第二个操作数所在的寄存器
<shifter_operand>:为第一个操作数。
适用范围有
[1]立即数、 rsb r0, r1, #0x08 r0 = 0x08 -r1
[2]寄存器、 rsb r0, r1, r2 r0 = r2 - r1
[3]寄存器 + 移位 rsb r0, r1, r2, lsl #2 r0 = r2 << 2 - r1
注意:
rsb r0, #0x08, r1 这是语法错误
和为零的两个数互为相反数
6)qemu仿真调试软件
支持多种CPU架构(arm、mips、ppc、x86),可以模拟arm处理器执行指令的过程
qemu安装
sudo apt install qemu
sudo apt install quem-user
sudo apt install quem-user-static
sudo apt install quem-system-arm
编译汇编代码
arm-cortex_a9-linux-gnueabi-as xxx.s -o xxx.o -g
arm-cortex_a9-linux-gnueabi-ld xxx.o -o xxx
注意:
为了方便使用qemu工具调试,我们添加了-g选项
xxx是文件名
程序真正的入口是__start函数
@计算两个数值的最小公约数
【1】启动qemu服务器
qemu-arm -g port xxx
注意:
在port处指定你的端口号(在端口号范围内就行)
xxx为你要执行的文件名
例如:
qemu-arm -g 1234 sum
指定服务器的端口号为1234执行sum文件
【2】启动qemu的客户端
arm-cortex_a9-linux-gnueabi-gdb xxx
(使用交叉编译工具链自带的gdb进行调试)
target remote localhost:port
注意:
xxx是文件名
port为你在服务端指定的端口号
【3】gdb的使用
l:显示文件内容,一次显示十行
b num:在第num行打断点
c:continue继续执行
info reg:打印ARM核的所有通用寄存器信息
info reg r0:打印r0寄存器的信息
n:继续执行下一行
until num:直接运行至第num行
clear num:删除num行设置的断点
q:退出调试
7)位运算指令 AND、ORR、EOR、BIC
指令介绍:
AND指令将<shifter_operand>表示的数值与寄存器<Rn>的值按位作逻辑与操作,并把结果保存到目标寄存器<Rd>中,同时根据操作的结果更新CPSR中相应的条件标志位。
编码格式:
语法格式:
AND{<cond>}{S} <Rd>, <Rn>, <shifter_operand>}
<cond>:指令执行的条件码。(可选)
当<cond>忽略时,指令为无条件执行
S:决定指令的操作是否影响CPSR中条件标志位的值。(可选)
当没有S时指令不更新CPSR中条件标志位的值。
当有S时指令更新CPSR中条件标志位的值;
①目标寄存器<Rd>为R15,则当前处理器模式对应的SPSR的值被复制到CPSR寄存器中,对于用户模式和系统模式,由于没有相应的SPSR,指令执行的结果将不可预料。
②目标寄存器<Rd>不是R15,指令根据传送的数值设置CPSR中的N位和Z位,并根据移位器的进位值carryout设置CPSR的C位,CPSR中的其他位不受影响。
<Rd>:目标寄存器
<Rn>:寄存器,为第一个操作数所在的寄存器
<shifter_operand>:为第二个操作数。
适用范围有
[1]立即数、 and r0, r1, #0x08 r0 = r1 & 0x08
[2]寄存器、 and r0, r1, r2 r0 = r1 & r2
[3]寄存器 + 移位 and r0, r1, r2, lsl #2 r0 = r1 & r2 << 2
指令介绍:
ORR指令将<shifter_operand>表示的数值与寄存器<Rn>的值按位作逻辑或操作,并把结果保存到目标寄存器<Rd>中,同时根据操作的结果更新CPSR中相应的条件标志位。
编码格式:
语法格式:
ORR{<cond>}{S} <Rd>, <Rn>, <shifter_operand>}
<cond>:指令执行的条件码。(可选)
当<cond>忽略时,指令为无条件执行
S:决定指令的操作是否影响CPSR中条件标志位的值。(可选)
当没有S时指令不更新CPSR中条件标志位的值。
当有S时指令更新CPSR中条件标志位的值;
①目标寄存器<Rd>为R15,则当前处理器模式对应的SPSR的值被复制到CPSR寄存器中,对于用户模式和系统模式,由于没有相应的SPSR,指令执行的结果将不可预料。
②目标寄存器<Rd>不是R15,指令根据传送的数值设置CPSR中的N位和Z位,并根据移位器的进位值carryout设置CPSR的C位,CPSR中的其他位不受影响。
<Rd>:目标寄存器
<Rn>:寄存器,为第一个操作数所在的寄存器
<shifter_operand>:为第二个操作数。
适用范围有
[1]立即数、 orr r0, r1, #0x08 r0 = r1 | 0x08
[2]寄存器、 orr r0, r1, r2 r0 = r1 | r2
[3]寄存器 + 移位 orr r0, r1, r2, lsl #2 r0 = r1 | r2 << 2
指令介绍:
EOR指令将<shifter_operand>表示的数值与寄存器<Rn>的值按位作逻辑异或操作,并把结果保存到目标寄存器<Rd>中,同时根据操作的结果更新CPSR中相应的条件标志位。
编码格式:
语法格式:
EOR{<cond>}{S} <Rd>, <Rn>, <shifter_operand>}
<cond>:指令执行的条件码。(可选)
当<cond>忽略时,指令为无条件执行
S:决定指令的操作是否影响CPSR中条件标志位的值。(可选)
当没有S时指令不更新CPSR中条件标志位的值。
当有S时指令更新CPSR中条件标志位的值;
①目标寄存器<Rd>为R15,则当前处理器模式对应的SPSR的值被复制到CPSR寄存器中,对于用户模式和系统模式,由于没有相应的SPSR,指令执行的结果将不可预料。
②目标寄存器<Rd>不是R15,指令根据传送的数值设置CPSR中的N位和Z位,并根据移位器的进位值carryout设置CPSR的C位,CPSR中的其他位不受影响。
<Rd>:目标寄存器
<Rn>:寄存器,为第一个操作数所在的寄存器
<shifter_operand>:为第二个操作数。
适用范围有
[1]立即数、 eor r0, r1, #0x08 r0 = r1 ^ 0x08
[2]寄存器、 eor r0, r1, r2 r0 = r1 ^ r2
[3]寄存器 + 移位 eor r0, r1, r2, lsl #2 r0 = r1 ^ r2 << 2
指令介绍:
BIC指令将<shifter_operand>表示的数值与寄存器<Rn>的值的反码按位作逻辑与操作,并把结果保存到目标寄存器<Rd>中,同时根据操作的结果更新CPSR中相应的条件标志位。
编码格式:
语法格式:
BIC{<cond>}{S} <Rd>, <Rn>, <shifter_operand>}
<cond>:指令执行的条件码。(可选)
当<cond>忽略时,指令为无条件执行
S:决定指令的操作是否影响CPSR中条件标志位的值。(可选)
当没有S时指令不更新CPSR中条件标志位的值。
当有S时指令更新CPSR中条件标志位的值;
①目标寄存器<Rd>为R15,则当前处理器模式对应的SPSR的值被复制到CPSR寄存器中,对于用户模式和系统模式,由于没有相应的SPSR,指令执行的结果将不可预料。
②目标寄存器<Rd>不是R15,指令根据传送的数值设置CPSR中的N位和Z位,并根据移位器的进位值carryout设置CPSR的C位,CPSR中的其他位不受影响。
<Rd>:目标寄存器
<Rn>:寄存器,为第一个操作数所在的寄存器
<shifter_operand>:为第二个操作数。
适用范围有
位清除指令
当shifter_operand为1,则对应的位的值为0
当shifter_operand为0,则对应的位的值保持不变
bic r0, r0, #0x08 @将r0中的bit3清零,其他位不变
8)比较测试指令 CMP、TST、TEQ
指令介绍:
CMP指令从寄存器<Rn>中减去<shifter_operand>表示的数值,根据操作的结果更新CPSR中相应的条件标志位,后面的指令就可以根据CPSR中相应的条件标志位来判断是否执行。
编码格式:
语法格式:
CMP{<cond>} <Rn>, <shifter_operand>}
<cond>:指令执行的条件码。(可选)
当<cond>忽略时,指令为无条件执行
<Rn>:寄存器,为第一个操作数所在的寄存器
<shifter_operand>:为第二个操作数。
注意:
CMP指令与SUBS指令的区别在于CMP指令不保存操作结果,操作的结果会存放在ALU内
ALU(算术逻辑单元)一个硬件,真实存在,专门用来做算术逻辑运算的器件
指令介绍:
TST指令将<shifter_operand>表示的数值与寄存器<Rn>的值按位作逻辑与操作,根据操作的结果更新CPSR中相应的条件标志位。
编码格式:
语法格式:
TST{<cond>} <Rn>, <shifter_operand>}
<cond>:指令执行的条件码。(可选)
当<cond>忽略时,指令为无条件执行
<Rn>:寄存器,为第一个操作数所在的寄存器
<shifter_operand>:为第二个操作数。
注意:
TST指令通常用于测试寄存器中某个(些)位是1还是0
tst r0, #0x80 @测试r0的bit3是否等于0
指令介绍:
TEQ指令将<shifter_operand>表示的数值与寄存器<Rn>的值按位作逻辑异或操作,根据操作的结果更新CPSR中相应的条件标志位。
编码格式:
语法格式:
TEQ{<cond>} <Rn>, <shifter_operand>}
<cond>:指令执行的条件码。(可选)
当<cond>忽略时,指令为无条件执行
<Rn>:寄存器,为第一个操作数所在的寄存器
<shifter_operand>:为第二个操作数。
注意:
TEQ指令通常用于比较两个数是否相等,这种比较操作通常不影响CSPR寄存器中的V位和C位
TEQ指令也可以用于比较两个操作数符号是否相同,该指令执行后,CPSR寄存器中的N位为两个操作数符号位作异或操作的结果
teq r0, #0x08 @比较r0寄存器中的值是否等于0x08
3、总结
{cond} 条件码是先决条件,只要指令加入了条件码,则执行该指令时,先去判断CPSR寄存器的状态标志位,根据结果去执行或不执行汇编指令
{S} 影响CPSR寄存器的NZCV位,只要指令加入了设置状态码,则执行完该指令后,根据指令的执行结果去设置CPSR寄存器NZCV位的值,属于后置条件,
CMP、TST、TEQ这三条指令不加了设置状态码也会影响CPSR寄存器的NZCV位
<shifter_operand>有三种形式
【1】立即数
【2】寄存器
【3】寄存器移位之后的值
LSL 逻辑左移 空位补0 LSR 逻辑右移 空位补0 ASR 算数右移 最高位补符号位 ROR 循环右移 被移出的位将重新插入到最高位 ROX 带扩展位的循环右移 新的最高位由CPSR的C位补充,拿最低位更新CPPSR的C位
跳转指令:B、BL、BX
算术指令:ADD、ADC、SUB、SBC
ADC比ADD多了一个加C位
SBC比SUB多了一个加NOT(C位)
数据传输指令:MOV、MVN
区别就是MVN是数据取反传输
位运算指令:AND、ORR、EOR、BIC
比较测试指令:CMP、TST、TEQ
三、任务
1、求两个数据的最大公约数(汇编实现)