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 數值不變