比较指令
- CMP, CMN,TEQ, TST这几条指令,总是会更新条件标志位,但运算结果总是被扔掉,不会进行保存。
他们的语法格式如下
CMP{cond} Rn, Operand2;Rn - Operand2 操作类似SUBS(除了扔掉运算结果)
CMN{cond} Rn, Operand2;Rn + Operand2 操作类似ADDS(除了扔掉运算结果)
TEQ{cond} Rn, Operand2;Rn EOR Operand2 操作类似EORS(除了扔掉运算结果)
TST{cond} Rn, Operand2;Rn AND Operand2 操作类似ANDS(除了扔掉运算结果)
tst:逻辑处理指令,用于把一个寄存器的内容和另一个寄存器的内容或立即数进行按位的与运算,并根据运算结果更新CPSR中条件标志位的 值。当前运算结果为1,则Z=0;当前运算结果为0,则Z=1
cmp:算数处理指令,用于把一个寄存器的内容和另一个寄存器的内容或立即数进行减法比较,不存储结果,可能都会更改BZCV标志位。Z位是最好理解的,只有运算的结果所有的位都为0则,Z置位。
CMN R1,R0 ;将寄存器R1的值与寄存器R0的值相加,并根据结果设置CPSR的标志位。只有运算的结果所有的位都为0则,Z置位。
TEQ R1,R2 ;将寄存器R1的值与寄存器R2的值按位异或,并根据结果设置CPSR的标志位
bne: 数据跳转指令,标志寄存器中Z标志位不等于零时, 跳转到BNE后标签处
beq: 数据跳转指令,标志寄存器中Z标志位等于零时, 跳转到BEQ后标签处
beq:
“beq run_on_dram” 如果 r0 - r1 = 0 ,程序跳转到run_on_dram处,再向下执行,此时CPSR的Z标识位为1,我们可以理解为:cmp的结果为0,或者CPSR的Z标识位为1时,程序跳转到beq 后的标签处;
bne:
“bne clear_loop” 如果 r0 - r1 != 0 ,程序跳转到clear_loop处,再向下执行,此时CPSR的Z标识位为0,我们可以理解为:cmp的结果为1,或者CPSR的Z标识位为0时,程序跳转到bne 后的标签处;
备注:对TEQ和TST来说不会影响到V标志,N位和Z位会根据操作结果会被更新,Operand2移位操作也可能会影响到C位。而CMP和CMN则根据运算结果都有可能会被影响到。
下面我们来说说,什么情况下这四个位会被置位/清除
条件标志 | 置位/清除 |
---|---|
N | 当运算的结果为负数的话置位,其他情况清0 |
Z | 当运算的结果为0的话置位,其他情况清0 |
C | 当运算的结果产生进位或者减法运算没有借位的话置位,其他情况清0 |
V | 当运算的结果产生溢出的话置位,其他情况清0 |
---------------------------上诉部分转自:https://www.jianshu.com/p/0c6192da2fd0------------------
所有ARM数据处理指令的乘法指令均可选择使用S后缀,并影响状态标志位。而其它指令一般不允许加S后缀,如B 、LDR、SWI、MRS等。
N 运算结果的最高位反映在该标志位。对于有符号二进制补码,结果为负数时N=1,结果为正数或零时N=0;
例如:执行movs r0,#0x7FFFFFFF后N=0;因为R0最高位为0
执行movs r0,#0x80000000后N=1;因为R0最高位为1
执行CMP r0,r0后N=0;因为R0-R0=0x00000000;
故N一般看目标寄存器的最高位,即N = Rd[31]。
Z 指令结果为0时Z=1(通常表示比较结果“相等”),否则Z=0;
例如:执行CMP r0,r0后Z=1
执行MOVS R0,#0后Z=1
故Z一般看目标寄存器的值是否为0,Rd=0时Z=1,否则Z=0。
C 当进行加法运算(包括CMN指令),并且最高位产生进位时C=1,否则C=0。当进行减法运算(包括CMP 指令),
并且最高位产生借位时C=0,否则C=1。对于结合移位操作的非加法/减法指令,C为从最高位最后移出的值,
其它指令C通常不变;
例如:执行 mov r0,#0xF0000000
ADDS R0,R0,R0
后C=1;
执行 SUBS R2,R2,R2后C=1,因为R2-R2=0不需要借位。
执行 CMP R3,R3后C=1;
执行 MOV R1,0x80000000
movs r0,r1 ,lsr #32
后C=1;
执行 mov r0,#0x10
mov r1,#0x7FFFFFFF
subs r3,R0,r1 ,lsr #1
后C=0;
总之,一般情况下加法进位,减法无借位时C=1; 对于结合移位操作的非加/减法指令,C为最后移出的值。
V 当进行加法/减法运算,并且发生有符号溢出时V=1,否则V=0,其它指令V通常不变。
例如:执行 mov r1,#0x80000000
adds r1,r1,r1 后V=1;
执行 mov r1,#0x70000000
adds r1,r1,r1 或 CMN R1,R1 后V=1;
执行 LDR R0,=0x8000000
LDR R1,=0x7FFFFFFF
CMP R0,R1 后V=1 ;
总之,两个负数运算结果第31位为0,则V=1
两个正数运算结果第31位为1,则V=1。
另外THUMB指令一般不需要S后缀,便能影响状态标志位。
如 在THUMB状态下下面两条指令相同
movs r0,#0x00
mov r0,#0x00
MOV一般不影响CPSR, 除非执行类似MOV pc, lr,效果上等同于BX lr
MOVS总是会影响CPSR, 包括N,Z,C标志位
执行MOV pc, lr,可能会影响到T标志位,执行MOVS pc, lr时,CPSR会被SPSR覆盖(内核态)
在Thumb代码里不能使用B跳转到ARM代码,因为T标志不会切换,即使跳到ARM代码,
也会按照Thumb方式来执行,BX是跳特殊指令,会根据目标寄存器地址来切换T标志。
转自 :http://www.eeworld.com.cn/mcu/article_2016051126281.html
--------------------------------------------------------------
之前以为CMP指令执行后,不管是进位还是借位,C标志位都会置位,其实这是错的,所以我整理了一下四个ARM标志位的置位和清零的规则:
N 当用两个补码表示的带符号数进行运算时,N=1表示运算的结果为负数;N=0表示运算的结果为正数或零.
Z Z=1表示运算的结果为零,Z=0表示运算的结果非零。
C 可以有4种方法设置C的值:
加法运算(包括CMN):当运算结果产生了进位时(无符号数溢出),C=1,否则C=0。
减法运算(包括CMP):当运算时产生了借位时(无符号数溢出),C=0,否则C=1。
对于包含移位操作的非加/减运算指令,C为移出值的最后一位。
对于其它的非加/减运算指令,C的值通常不会改变。
V 可以有2种方法设置V的值:
对于加减法运算指令,当操作数和运算结果为二进制的补码表示的带符号数时,V=1表示符号位溢出
对于其它的非加/减运算指令,V的值通常不会改变。
0000 = EQ - Z set (equal,相等)
0001 = NE - Z clear (not equal,不相等)
0010 = CS - C set (unsigned higher or same,无符号大于或等于)
0011 = CC - C clear (unsigned lower,无符号小于)
0100 = MI - N set (negative,负数)
0101 = PL - N clear (positive or zero,正数或零)
0110 = VS - V set (overflow,溢出)
0111 = VC - V clear (no overflow,未溢出)
1000 = HI - C set and Z clear (unsigned higher,无符号大于)
1001 = LS - C clear or Z set (unsigned lower or same,无符号小于或等于)
1010 = GE - N set and V set, or N clear and V clear (greater or equal,带符号大于或等于)
1011 = LT - N set and V clear, or N clear and V set (less than,带符号小于)
1100 = GT - Z clear, and either N set and V set, or N clear and V clear (greater than,带符号大于)
1101 = LE - Z set, or N set and V clear, or N clear and V set (less than or equal,带符号小于或等于)
1110 = AL - always
1111 = NV - never
---------------------
转自:https://blog.csdn.net/nanfangqiulin/article/details/51122718