AlessandroF
AlessandroF

Reputation: 562

How to find N,C,Z,V flags after the execution of this ARM assembly code program?

Giving the following ARM assembly code, find the the output of the ALU flags [Negative, Carry out, Zero, oVerflow]

MOV R0 #00000100
MOV R1 #00000100
MOV R2 #0000010A
CMP R0, R1
SUBGES R0, R0, R2
ADDLTS R0, R1, R2 

The correct answer should be N=1 ; C=V=Z=0 but I'm not sure about it. Also, I'm not even sure if #00000100 is binary, decimal or hexadecimal.
Anyways, considering all of them hexadecimal, I'm proceeding in this way:

CMP R0 R1

Gives as ALU flags Z=1 and C=V=N=0.

SUBGES R0, R0, R2

performs a subtracion if "Greater or equal" (checks if N==V). Since N=V,
R0-R2 = 256 - 266 = -10
Recall that "S" uodates flags, N=1, C=Z=V=0.

ADDLTS R0, R1, R2

performs an addition if "Less Than" (checks if N!=V). Since N!=V,
R1 + R2 = 256 + 266 = 522
It means that N=C=Z=V=0.
Where am I wrong?

Upvotes: 1

Views: 2634

Answers (2)

AlessandroF
AlessandroF

Reputation: 562

Update for those who may be interested in this question:
My professor made a mistake, that's all. The correct answer is that I wrote.

Upvotes: 0

artless-noise-bye-due2AI
artless-noise-bye-due2AI

Reputation: 22395

The correct answer makes sense if the instructions are subge and addlt. It is rare (but is possible) to have a conditional and set. Usually this would be an error. See for instance the example below from the ARM ARM 2nd edition by David Seal,

/* C code for Euclid’s Greatest Common Divisor (GCD)*/
/* Returns the GCD of its two parameters */
int gcd(int a, int b)
{
  while (a != b)
    if (a > b )
      a = a - b ;
    else
      b = b - a ;
  return a ;
}

; ARM assembler code for Euclid’s Greatest Common Divisor
; On entry: R0 holds ‘a’, R1 holds ‘b’
; On exit : R0 hold GCD of A and B
gcd:
 CMP    R0, R1        ; compare ‘a’ and ‘b’
 SUBGT  R0, R0, R1    ; if (a>b) a=a-b (if a==b do nothing)
 SUBLT  R1, R1, R0    ; if (b>a) b=b-a (if a==b do nothing)
 BNE    gcd           ; if (a!=b) then keep going
 MOV    PC, LR        ; return to caller

It is very dense code that would both execute conditionally and set flags. An obvious counter is (also from ARM ARM 2nd edition),

if (a==0 || b==1)
  c = d + e ;

CMP    R0, #0      ; compare a with 0
CMPNE  R1, #1      ; if a is not 0, compare b to 1
ADDEQ  R2, R3, R4  ; if either was true c = d + e

If everything in your question is correct, then the correct answer is wrong.

CMP R0, R1
SUBGES R0, R0, R2
ADDLTS R0, R1, R2  ; why bother setting conditions here? 

This maps to,

   if(a <= b) {
     if(a <= c)
       a = b + c;
     else
       /* a = a */ ;
   } else {
       a = a - c;
   }

which leaves the case a <= b && a > c as the original a. It is possible, but it seems a little contrived. The form,

CMP R0, R1
SUBGE R0, R0, R2
ADDLT R0, R1, R2 

Is much more practical. If somehow this is Thumb2 code with a preceding IT, and you missed disassembling it, then disassembly will present subge as subs if things are correct. It could be some sort of disassembler bug; but it seems like a paper and pencil homework question. I guess a point here is that in Thumb2 and unified assembler, these forms (subges/addlts) aren't even allowed.

Upvotes: 1

Related Questions