Expand/Shrink

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 --- 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0
ROTATE LIT8
SHIFTH
COND OOO OPCODE S RN RD RS V SHFT Z RM
and Rd, Rn, Rm OP # cond 0 0 0 0 0 0 0 S Rn Rd shift# shft 0 Rm
and Rd, Rn, Rm OP Rs cond 0 0 0 0 0 0 0 S Rn Rd Rs 0 shft 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 ---- 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  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.