Still looking at ARM assembler semantics (and, I try hard to read the specification, I ensure you!!!). I have some doubts about the ARM bit-shift instructions in general and RRX in particular.

Lets start with RRX.

From Davespace, Introduction to ARM, section Barrel Shifter, we see that RRX correspond to:

RRX: Barrel RollRotate Right Extended

I suppose the C to be the carry flag found in the CPSR, is it correct ?

Second question, in the case of the following instruction:

ands   r9, r0, r0, ror #3

I read that the carry flag (C) is set to the value of the last bit shifted out by the shifter operand (here ROR).

My problem is that the ands is also supposed to update the CPSR because of its flag s. So, who is winning at the end ? And, what is left in the final carry flag ? The value resulting of AND or the value resulting of ROR ?

  • I know that I should try, but I have no easy ARM platform with a debugger at hand reach by now... (though an ARM QEmu could do it as well...). – perror Aug 13 '14 at 13:50
  1. Yes, C is the carry flag.

  2. C is set from the result of the ROR operation.

Pseudocode of the AND (register) instruction from the ARM ARM:

if ConditionPassed() then
    (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
        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
    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
  • Igor, if I meet you in real life at some point, remember me to offer you a drink (what ever you want!). :-) – perror Aug 13 '14 at 14:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.