您的位置:首页 > 其它

ARM 条件码 分支指令 比较指令 程序状态寄存器(CPSR)

2012-09-13 10:16 711 查看
ARM中的程序状态寄存器(CPSR)

31 30 29 28 27 26       7  6  5  4  3  2  1  0
N  Z  C  V  Q  DNM(RAZ) I  F  T  M4 M3 M2 M1 M0
|  |  |  |____ Overflow : (Signed) Overflow/Underflow : The V flag works the same as the C flag, but for signed operations.
|  |  |        the result of which will not fit into a 32bit destination register.
|  |  |_______ Carry : (Unsigned) Overflow/Underflow :
|  |           The C flag is set if the result of an Unsigned operation overflows the 32-bit result register.
|  |           the result of which will not fit into a 32bit destination register.
|  |           Basically the Carry flag is just the carry-out of the 32-bit adder (ie. bit 32).
|  |__________ Zero : The Z flag is set if the result of the flag-setting instruction is zero.
|_____________ Negative : The N flag is set by an instruction if the result is negative.
In practice, N is set to the two's complement sign bit of the result (bit 31).

For example, 0x7fffffff is the largest positive two's complement integer that can be represented in 32 bits,
so 0x7fffffff + 0x7fffffff = 0xFFFFFFFE triggers a signed overflow, V=1
but not an Unsigned overflow (or carry) C=0 :

the result, 0xfffffffe, is correct if interpreted as an Unsigned quantity,
but represents a negative value (-2) if interpreted as a signed quantity.

Consider the following example:

ldr r1, =0xffffffff
ldr r2, =0x00000001
adds r0, r1, r2

The result of the operation would be 0x1-00000000,
but the top bit is lost because it does not fit into the 32-bit destination register and
so the real result is 0x00000000.

In this case, the flags will be set as follows:
N = 0 : bit31 of result
Z = 1 : result is 0
C = 1 : bit32 of result : 4294967295 + 1 = 4294967296 : We lost some data because the result did not fit into 32 bits
V = 0 : (-1) + 1 = 0 : That operation clearly does not overflow

NV                          NeVer, so very useful. You should not use this code anyway
AL                          ALways, the default condition so does not need to be specified

EQ      Z==1                Equal                               : Z set
NE      Z==0                Not equal                           : Z clear

MI      N==1                Minus/negative                      : N set
PL      N==0                Plus/positive or zero               : N clear

 CS     C==1            Unsigned overflow                   : C set
 CC     C==0             Unsigned No overflow              : C clear

VS      V==1                Signed overflow                     : V set
VC      V==0                Signed No overflow                  : V clear

 LO     C==0             Unsigned lower                   : C clear
LS     C==1 || Z==0       Unsigned lower or same          : C clear or Z set
 HS     C==1            Unsigned higher or same            : C set
HI   C==1 && Z==0       Unsigned higher              : C set and Z clear

  LT      N != V              Signed less than                    : N != V
LE      Z == 1 || N != V    Signed less than or equal           : Z == 1 || N != V
GE      N == V              Signed greater than or equal        : N == V
GT      Z == 0 && N == V    Signed greater than                 : Z == 0 && N == V


Here follows a list of available conditional codes:

AL - ALways, the default condition so doesn't need to be specified
NV - NeVer, so very useful. You should not use this code anyway...

VS - Overflow Set If the V flag is set after an arithmetical operation,
the result of which will not fit into a 32bit destination register.
VC - Overflow Clear If the V flag is clear, the reverse of VS.
PL - Plus If the N flag is clear after an arithmetical operation.
For the purposes of defining 'plus', zero is positive because it isn't negative...
MI - Minus  If the N flag is set after an arithmetical operation.

EQ - Equal  If the Z flag is set after a comparison.
NE - Not Equal  If the Z flag is clear after a comparison.
HI - Higher Than (Unsigned) If after a comparison the C flag is set AND the Z flag is clear.
LS - Lower Than or Same (Unsigned)  If after a comparison the C flag is clear OR the Z flag is set.

CS - Carry Set  Set if the C flag is set after an arithmetical operation OR a shift operation,
the result of which cannot be represented in 32bits.
You can think of the C flag as the 33rd bit of the result.
CC - Carry Clear  The reverse of CS.

GE - Greater Than or Equal (signed) If after a comparison...
the N flag is set AND the V flag is set or...
the N flag is clear AND the V flag is clear.

GT - Greater Than (signed)  If after a comparison...
the N flag is set AND the V flag is set or...
the N flag is clear AND the V flag is clear and... the Z flag is clear.

LE - Less Than or Equal To (signed) If after a comparison...
the N flag is set AND the V flag is clear or...
the N flag is clear AND the V flag is set and... the Z flag is set.

LT - Less Than (signed) If after a comparison...
the N flag is set AND the V flag is clear or...
the N flag is clear AND the V flag is set.

AL - Always The default condition, so does not need to be explicity stated.
NV - Never Not particularly useful, it states that the instruction should never be executed. A kind of Poor Mans' NOP.
NV was included for completeness (as the reverse of AL), but you should not use it in your own code.

BEQ   Branch if EQual
BNE   Branch if Not Equal
BVS   Branch if oVerflow Set
BVC   Branch if oVerflow Clear
BHI   Branch if HIgher
BLS   Branch if Lower or the Same
BPL   Branch if PLus
BMI   Branch if MInus

  BCS   Branch if Carry Set
  BHS   Branch if Higher or Same
BCC   Branch if Carry Clear
  BLO   Branch if LOwer


BGE   Branch if Greater than or Equal
BGT   Branch if Greater Than
BLE   Branch if Less than or Equal
BLT   Branch if Less Than

Somewhere in the specifications of ARM CPUs it states that CMP is like a SUB instruction without register overwrite

mov  r0,0
mov  r1,1
cmp  r0,r1

As "cmp r0,r1" is equivalent to "sub r0,r0,r1" (without writing r0) and equivalent to "r0 - r1"
then the Carry flag (C) should be set in this example, but IT IS NOT, at least for the CMP instruction.

This means that the CS (Carry Set) and CC (Carry Clear) condition codes must be interpreted inverted:
CC : "r0 Unsigned lower than r1",           (normally r0 > r1)
CS : "r0 Unsigned higher or same than r1",  (normally r0 <= r1)

This leads to weird condition codes for comparing and branching, for people that have been programming i86 and 68000.
Is this a specification fault of ARM?

Yes, it's different from some architectures
It's not wrong, it's just different. ARM uses C as a NOT-borrow flag for subtraction operations.

Borrow is the inverted Carry:
r0 <  r1: r0 + complement2(r1)  -> Carry Clear
r0 >= r1: r0 + complement2(r1)  -> Carry Set

Because, when using ADD with the 2complement of the substractor,
and substractor is higher, the Carry is not set (Borrow).
But if the substractor is lower, and adding its 2complement, the carry is set (Borrow).

You mean that when using SUB it negates the Carry,very advanced. :)
Maybe it uses a complement2() and Add() the ARM processor, when instructing a SUB.

Basically the Carry flag is just the carry-out of the 32-bit adder (ie. bit 32).
There is no borrow flag or anything similar.

The ARM-ARM explicitly states that subtract is done
by inverting the input and forcing the carry input flag to 1.

You're right that the meaning of that carry flag depends on the operation you've done,
after an add it gives you Unsigned overflow, after subtract it tells you which operand is larger.
If you use CC/CS for add, and LO/HI/LS/HS for sub
then you can avoid having to think about the details...

All ALUs use ones-complement and set the carry-in to implement subtract.
This is almost the same as your complement2()
except when both operands are zero (0 + 0 gives carry clear, 0 - 0 gives carry set).

条件码标志
N、Z、C、V均为条件码标志位。它们的内容可被算术或逻辑运算的结果所改变, 并且可以决定某条指令是否被执行。条件码标志各位的具体含义如下表所示:
N——本位设置成当前指令运算结果的bit[31]的值。当两个表示的有符号整数运算时, n=1表示运算结果为负数, n=0表示结果为正书或零。
Z——Z=1表示运算的结果为零;Z=0表示运算的结果不为零。对于CMP指令, Z=1表示进行比较的两个数大小相等。
V——对于加减运算指令, 当操作数和运算结果为二进制的补码表示的带符号数时, V=1表示符号为溢出;通常其他指令不影响V位。
C——下面分四种情况讨论C的设置方法:
在加法指令中(包括比较指令CMN), 当结果产生了进位,则C=1,表示无符号运算发生上溢出;其他情况C=0。
在减法指令中(包括比较指令CMP), 当运算中发生借位, 则C=0, 表示无符号运算数发生下溢出;其他情况下C=1。
对于包含移位操作的非加减运算指令, C中包含最后一次溢出的的位的数值,
对于其他非加减运算指令, C位的值通常不受影响

指令的条件码
条件码 助记符后缀   标 志                 含 义
1111  NV            忽略
1110  AL            忽略                  无条件执行

0000  EQ            Z置位                 相等
0001  NE            Z清零                 不相等

0100  MI            N置位                 负数
0101  PL            N清零                 正数或零

0110  VS            V置位                 溢出
0111  VC            V清零                 未溢出

1001  LS            C清零Z置位            无符号数小于或等于
1000  HI            C置位Z清零            无符号数大于
0010  CS            C置位                 无符号数大于或等于
0010  HS            C置位                 无符号数大于或等于
0011  CC            C清零                 无符号数小于
0011  LO            C清零                 无符号数小于

1010  GE            N等于V                带符号数大于或等于
1011  LT            N不等于V              带符号数小于
1100  GT            Z清零且(N等于V)     带符号数大于
1101  LE            Z置位或(N不等于V)   带符号数小于或等于

比较指令通常用于把一个寄存器与一个32位的值进行比较或测试.
比较指令根据结果更新cpsr的标志位,但不影响参与比较的寄存器内容.
在设置标志位后,其他指令可通过条件执行来改变程序的执行流程.
对于比较指令,不需要使用S后缀就可以改变标志位.

指令语法:<指令>{<cond>} Rn, Rs // 其中Rs是桶形移位器的操作结果
CMN   取负比较    标记根据 Rn + Rs 的值设置
CMP   比较        标记根据 Rn - Rs 的值设置
TEQ   等值测试    标记根据 Rn ^ Rs 的值设置
TST   位测试      标记根据 Rn & Rs 的值设置

cmp     Works like subs, but does not store the result.
cmn     Works like adds, but does not store the result.
tst     Works like ands, but does not store the result.
teq     Works like eors, but does not store the result.

CMP/CMN 比较指令本质上就是一个不返回运算结果的减法指令;
TST     指令就是一个没有保存结果的逻辑与操作;
TEQ     则是一个逻辑异或操作.对于每个操作,不需要保存结果,只根据结果影响cpsr.

//------------------------------------------------------------------------------------------------------------------------------
// 关于C、V值更多的解释
//------------------------------------------------------------------------------------------------------------------------------

处理器对两个操作数进行运算时,
按照无符号数求得结果, 并相应设置进位标志C;
同时, 根据是否超出有符号数的范围设置溢出标志V。
如果将参加运算的操作数认为是无符号数, 就应该关心进位;
如果将参加运算的操作数认为是有符号数, 则要注意是否溢出。

溢出标志V和进位标志C是两个意义不同的标志。

进位标志C表示无符号数运算结果是否超出范围 -- 运算结果仍然正确(部分)
溢出标志V表示有符号数运算结果是否超出范围 -- 运算结果已经不正确

处理器内部以补码表示有符号数,
8个二制位能够表达的整数范围是: +127 ~ -128,
16位表达的范围是: +32767 ~ -128。
如果运算结果超出了这个范围, 就是产生了溢出,
有溢出, 说明有符号数的运算结果需要考虑溢出情况。

判断运算结果是否溢出有一个简单的规则:
1 两个正数相加得到负数,就是溢出了. (或一个正数减一个负数)
2 两个负数相加得到正数,就是溢出了.
3 一个正数和一个负数相加不可能溢出
当两个相同符号数相加,而运算结果的符号与原数据符号相反时,产生溢出

3A + 7C=B6
无符号数运算:58+124=182 范围内,无进位
有符号数运算:58+124=182 范围外,有溢出

AA + 7C= 1 26
无符号数运算:170+124=294 范围外,有进位
有符号数运算:-86+124=38 范围内,无溢出

处理器对两个操作数进行运算时按照无符号数求得结果,
并相应设置进位标志CF - 根据是否超出有符号数的范围设置溢出标志OF。

x86处理器的EFLAGS的CF位和ARM的CSPR的C位,
在使用加法指令的时候对进位的影响是一样的,
如果有进位,那么x86处理器的EFLAGS的CF位,否则没有产生进位则CF被置0
如果有进位,那么ARM的CSPR的C位都置1,否则没有产生进位则C被置0

在使用减法指令的时候,
X86的做法是,如果产生借位,那么CF位置1,否则没有产生借位则CF被置0

ARM的做法是,如果减法产生借位(无符号数下溢)则C被置0, 否则没有产生借位(没有溢出)则C被置1
比如:1 - 2 被视为:1 + (-2) = 0x0000 0001 + 0xFFFF FFFE = 0xFFFF FFFF : 虽然产生了借位,但进位 CF 为0。因为没有跨过32位最大无符号数的界限。
又如:2 - 1 被视为:2 + (-1) = 0x0000 0002 + 0xFFFF FFFF = 0x0000 0001 : 虽然没有产生借位,但进位 CF 为1。因为跨过了32位最大无符号数的界限。
CF = Bit32

ADD     加法。
ADC     带进位加法。

SUB     减法。
SBC     带进位减法。

RSB     反向减法。
RSC     带进位反向减法(仅 ARM)。

ADC, ADD, RSB, SBC, and SUB

ADD{S} {Rd,} Rn, <Rm|#imm>
SUB{S} {Rd,} Rn, <Rm|#imm>
ADCS   {Rd,} Rn, Rm
SBCS   {Rd,} Rn, Rm
RSBS   {Rd,} Rn, Rm, #0

Operation

The ADD instruction adds the value in Rn to the value in Rm
or an immediate value specified by imm
and places the result in the register specified by Rd.

The ADDS instruction performs the same operation as ADD and also updates the N, Z, C and V flags.

The ADCS instruction adds the value in Rn to the value in Rm,
adding a further one if the carry flag is set,
places the result in the register specified by Rd and updates the N, Z, C, and V flags.

The SUB instruction subtracts the value in Rm or the immediate specified by imm.
It places the result in the register specified by Rd.

The SUBS instruction performs the same operation as SUB and also updates the N, Z, C and V flags.

The SBCS instruction subtracts the value of Rm from the value in Rn,
deducts a further one if the carry flag is set.
It places the result in the register specified by Rd and updates the N, Z, C and V flags.

The RSBS instruction subtracts the value in Rn from zero, producing the arithmetic negative of the value,
and places the result in the register specified by Rd and updates the N, Z, C and V flags.

Use ADC and SBC to synthesize multiword arithmetic, see Examples.

Example 3.1. 64-bit addition
ADDS    R0, R0, R2    ; add the least significant words
ADCS    R1, R1, R3    ; add the most significant words with carry

Example 3.1 shows two instructions that add a 64-bit integer contained in R0 and R1
to another 64-bit integer contained in R2 and R3,
and place the result in R0 and R1.

Example 3.2. 96-bit subtraction
SUBS    R4, R4, R1    ; subtract the least significant words
SBCS    R5, R5, R2    ; subtract the middle words with carry
SBCS    R6, R6, R3    ; subtract the most significant words with carry

Multiword values do not have to use consecutive registers.
Example 3.2 shows instructions that subtract a 96-bit integer contained in R1, R2, and R3
from another contained in R4, R5, and R6.
The example stores the result in R4, R5, and R6.

Example 3.3.  Arithmetic negation
RSBS    R7, R7, #0    ; subtract R7 from zero
Example 3.3 shows the RSBS instruction used
to perform a 1's complement of a single register.

CMP and CMN
Compare and Compare Negative.
Syntax
CMN Rn, Rm
CMP Rn, #imm
CMP Rn, Rm
where:
Rn    is the register holding the first operand.
Rm    is the register to compare with.
imm    is the immediate value to compare with.

Operation

These instructions compare the value in a register with either the value in another register or an immediate value.
They update the condition flags on the result, but do not write the result to a register.

The CMP instruction subtracts either the value in the register specified by Rm,
or the immediate imm from the value in Rn and updates the flags.
This is the same as a SUBS instruction, except that the result is discarded.

The CMN instruction adds the value of Rm to the value in Rn and updates the flags.
This is the same as an ADDS instruction, except that the result is discarded.

//------------------------------------------------------------------------------------------------------------------------------
// (经典解释):原码、反码和补码
//------------------------------------------------------------------------------------------------------------------------------
处理器内部以补码表示有符号数<无符号数> : 数值一律用补码来表示(存储)?

补码的设计目的是: 使减法运算转换为加法运算
两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃。

计算机里面,只有加法器,没有减法器,所有的减法运算,都必须用加法进行
计算时加上正数,是不需要进行求取补数的;
只有进行减法(或者加上负数),才需要对减数求补数。

二进制数的模

8 位二进制数的模可以按照十进制写成 2^8,1-0000-0000           按照十进制,它就是 256
16 位数二进制数的模可以按照十进制 2^16,1-0000-0000-0000-0000 按照十进制,它就是 65536

补码就是按照这个要求来定义的:正数不变,负数即用模减去绝对值

正数不变 : 正数的补码和原码相同 :  127 --> 0111-1111
负数补码 : 负数即用模减去绝对值 : -127 --> 256 - 127 = 129 --> 1000-0001
相当于是将其原码绝对值各位求反之后在末位再加1
: 127 --> 111-1111
: NOT --> 000-0000
: +1      000-0001
:         000-0001
:符号位 1 000-0001

正数的最高位都是0,负数的最高位都是1。
这最高位的1、0是自然出现的
-- 正数的补码都是和原码相同。
-- 负数的补码是负数即用模减去绝对值
-128 -127 .. -1 0 1 .. 127

一个数和它的补码是可逆的。已知一个数的补码,求原码的操作分两种情况 :

如果补码的MSB=“0”,表示是一个正数,所以补码就是该数的原码。
如果补码的MSB=“1”,表示是一个负数,求原码的操作可以是:
模减去绝对值 : 符号位为1,其余各位取反,然后再整个数加1。
1 0000-0000
- 1000-0001
-----------
0111-1111

8个二制位能够表达的整数范围是: +127 ~ -128,
16位表达的范围是: +32767 ~ -128。

无符号数  127               128       129             255         0         1             127             128

0-1111111 <---    1-0000000 1-0000001 ....  1-1111111   0-0000000 0-0000001 ... 0-1111111  ---> 1-0000000

有符号数  127 : Underflow   -128      -127            -1          0         1             127             -128 : Overflow
正数 <--- 负数    负数     符号位=1        负数           正数       符号位=0       正数        ---> 负数
数值取反 + 1                          数值不变
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: