# ARM data processing

### Data Processing opcodes

For x86, see adc, add, and, cmp, neg, not, or, sbb, sub, test, xor, and for other help misdirections/ambiguities see JavaScript’s classList.add(), or the hll and, or, xor, not logical operators
|=--- Instruction ---.|1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0| |.............................................................|.ROTATE|......LIT8.....| |.............................................................|..SHIFTH.|.............| |.....................|..COND.|.OOO.|.OPCODE|S|...RN..|...RD..|...RS..|V|=S2|Z|...RM..| |and Rd, Rn, Rm OP #..|..cond.|0 0 0|0 0 0 0|S|...Rn..|...Rd..|..shift#.|=s2|0|...Rm..| |and Rd, Rn, Rm OP Rs.|..cond.|0 0 0|0 0 0 0|S|...Rn..|...Rd..|...Rs..|0|=s2|1|...Rm..| |and Rd, Rn, #........|..cond.|0 0 1|0 0 0 0|S|...Rn..|...Rd..|.rotate|.......#.......|
The above is copied from the main table. Equivalently, perhaps a smidge clearer:
|=---- Operation ----.|1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0| |.....................|.COND..|.TA|I|OPCODE.|S|.RN....|.RD....|shifter_operand........| |add Rd, Rn, Rm Op #..|.cond..|0.0|0|0 1 0 0|S|.Rn....|.Rd....|.IS......|.ST|0|.Rm....| |add Rd, Rn, Rm Op Rs.|.cond..|0.0|0|0 1 0 0|S|.Rn....|.Rd....|.Rs....|0|.ST|1|.Rm....| |add Rd, Rn, #........|.cond..|0.0|1|0 1 0 0|S|.Rn....|.Rd....|rotate.|immediate......|
I bit Distinguishes between the immediate and register forms of <shifter_operand>.
S bit Signifies that the instruction updates the condition codes.
Note that S must be 1 and Rd 0 for cmp/cmn/tst/teq instructions.
If I is 0 and both V and Z are 1, it is (probably) a multiply instruction.
Rn Specifies the first source operand register.
Rd Specifies the destination register (must be 0 for tst/teq/cmp/cmn).
shifter_operand Specifies the second source operand (see ARM barrel shifter).

### opcodes

|Opcode.|Mnemonic|Operation....................|Action.............................................| |=0000..|..=and..|Logical.bitwise and_bits.....|Rd := and_bits(Rn,shifter_operand).................| |=0001..|..=eor..|Logical.bitwise xor_bits.....|Rd := xor_bits(Rn,shifter_operand).................| |=0010..|..=sub..|Subtract.....................|Rd := Rn - shifter_operand.........................| |=0011..|..=rsb..|Reverse Subtract.............|Rd := shifter_operand - Rn.........................| |=0100..|..=add..|Add..........................|Rd := Rn + shifter_operand.........................| |=0101..|..=adc..|Add with Carry...............|Rd := Rn + shifter_operand + Carry Flag............| |=0110..|..=sbc..|Subtract with Carry..........|Rd := Rn - shifter_operand - NOT(Carry Flag).......| |=0111..|..=rsc..|Reverse Subtract with Carry..|Rd := shifter_operand - Rn - NOT(Carry Flag).......| |=1000..|..=tst..|Test.........................|Update flags as per and_bits(Rn,shifter_operand)...| |=1001..|..=teq..|Test Equivalence.............|Update flags as per xor_bits(Rn,shifter_operand)...| |=1010..|..=cmp..|Compare......................|Update flags as per Rn - shifter_operand...........| |=1011..|..=cmn..|Compare Negated..............|Update flags as per Rn + shifter_operand...........| |=1100..|..=orr..|Logical bitwise or_bits......|Rd := or_bits(Rn,shifter_operand)..................| |=1101..|..=mov..|Move.........................|Rd := shifter_operand [no first operand]...........| |=1110..|..=bic..|Bit Clear....................|Rd := and_bits(Rn,not_bits(shifter_operand)).......| |=1111..|..=mvn..|Move bitwise not_bits........|Rd := not_bits(shifter_operand) [no first operand].|
See ARM barrel shifter for more details about shifter_operand.

### examples

|Instruction..........|Description..........................| |adds r0, r2, r4......|r0 := r2+r4, setting carry bit.......| |adcs r1, r3, r5......|r1 := r3+r5+c ["" for>64bits].....| |adc r0,r1............|shorthand for adc r0,r0,r1...........| |add r0, r1, 256......|r0 := r1 + 256.......................| |add r0, r2, r3 lsl 1.|r0 := r2 + r3*2......................| |add r4, r4, r4 lsl 4.|r4 *= 17.(aka r4*16+r4)..............| |and r7, r5, r9.......|r7 := and_bits(r5,r9)................| |and r0, r0, 3........|r0 := and_bits(r0,0b0011)............| |bic r0, 0b1011.......|r0 := and_bits(r0,not_bits(0b1011)...| |and r0, not r2.......|(phix-only-style unconditional bics).| |cmn r1, r2...........|status_flags:= r1 - (-r2)............| |cmn r1, 1............|equivalent to/emitted for cmp r1,-1..| |cmp r1, r2...........|status_flags:= r1 - r2...............| |cmp r0, 42...........|compare r0 to 42.....................| |cmn r0, 42...........|compare r0 to -42....................| |eor r1, r2, r3.......|r1 := xor_bits(r2,r3)................| |xor r1, r2, r3.......|(phix-only-style unconditional eors).| |orr r1, r2, r3.......|r1 := or_bits(r2,r3).................| |or r1, r2, r3........|(phix-only-style unconditional orrs).| |neg r0...............|r0 := -r0 (""/== rsb r0,0)...........| |not r0...............|r0 := not_bits(r0) (""/== mvn r0,r0).| |rsb r0, 4............|r0 := 4 - r0.........................| |rsb r0, r1...........|r0 := r1 - r0........................| |rsb r0, r1, 16.......|r0 := 16 - r1........................| |rsb r0, r1, r2.......|r0 := r2 - r1........................| |rsb r5, r5, r5 lsl 5.|r5 *= 31.(aka r5*32-r5)..............| |rsc r0, r1, r2.......|r0 := r2 - r1 - not(carry)...........| |sbc r0, r1, r2.......|r0 := r1 - r2 - not(carry)...........| |sub r0, r1, r2.......|r0 := r1 - r2........................| |subs r0, r1, 42......|r0 := r1 - 42, setting flags.........| |teq r1, r2...........|status_flags := xor_bits(r1,r2)......| |tst r1, r2...........|status_flags := and_bits(r1,r2)......| |test r1, r2..........|(phix-only-style unconditional tst)..|
The first two entries add two 64 bit numbers, with the result in r0 and r1, and the first 64 bit source in r2/3 and the second in r3/4. It would of course be trivial to extend that to a 128-bit addition of r0..3 := r4..7 + r8..11.
Note the phix-only-style use of and/or/xor/test may not have a conditional suffix, and the flags are always updated when using those aliases, an s suffix is implied/illegal/non-removable.
sub and sbc generate the carry flag the wrong way around, if a borrow is required then the carry flag is UNSET.
Thus, the sbc and rsc instructions require a NOT Carry flag - they invert the flag automatically during the instruction.
While mvn uses a 1’s compliment of it’s input (for good reason), cmn uses a (perhaps more sensible) 2’s compliment.
(Aside: I’m not passing any judgement on those design decisions, merely explaining their behaviour in the best way that I can think of.)
Unfortunately I am not confident enough to say much/anything at all about what happens when cmn uses the barrel shifter.
One thing I can repeat is that when Rn is 0 or #80000000, cmp Rn,0 leaves the C flag = 1 but cmn Rn,0 leaves the C flag = 0,
so it’s almost like cmp Rn,-op2, but not quite.
Both cmp a,b and teq a,b can be used as an equality test, the former affects the V flag, whereas the latter does not.
The teq instruction may? set the C flag from "shifter_carry_out", whereas cmp/cmn would immediately blat that.
The teq instruction updates the Z and N flags such that Z=1 if they are equal, and N=1 if their signs differ.