Yes, C
is the carry flag.
C
is set from the result of the ROR
operation.
Pseudocode of the AND (register)
instruction from the ARM ARM:
if ConditionPassed() then
EncodingSpecificOperations();
(shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
result = R[n] AND shifted;
if d == 15 then // Can only occur for ARM encoding
ALUWritePC(result); // setflags is always FALSE here
else
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
// APSR.V unchanged
As you can see, APSR.C
is set to the result of the shift operation, not the AND
operation.
Now, AND
is pretty straightforward but in case of e.g. ADD
you may have carry affected by both the shift and the add. So what happens? Again, ARM ARM to the rescue:
if ConditionPassed() then
EncodingSpecificOperations();
shift_n = UInt(R[s]<7:0>);
shifted = Shift(R[m], shift_t, shift_n, APSR.C);
(result, carry, overflow) = AddWithCarry(R[n], shifted, APSR.C);
R[d] = result;
if setflags then
APSR.N = result<31>;
APSR.Z = IsZeroBit(result);
APSR.C = carry;
APSR.V = overflow;
The answer: the add "wins" and the carry of the shift operation is discarded.
BTW, a good page to check what happens for each concrete instruction is here. For example:
ands r9, r0, r0, ror #3
machine code: E01091E0
...
cpsr.N ← (r0 AND r0 ROR 3)<31>
cpsr.Z ← r0 AND r0 ROR 3 = 0
cpsr.C ← #CARRY (ROR_C (r0,3))
r9 ← r0 AND r0 ROR 3
r15 ← r15 + 4
adds r9, r0, r0, ror #3
machine code: E09091E0
...
cpsr.N ← (r0 + r0 ROR 3)<31>
cpsr.Z ← r0 + r0 ROR 3 = 0
cpsr.C ← #CARRY (AddWithCarry (r0,r0 ROR 3,False))
cpsr.V ← #OVERFLOW (AddWithCarry (r0,r0 ROR 3,False))
r9 ← r0 + r0 ROR 3
r15 ← r15 + 4