m A
m A

Reputation: 11

Why the status flags in AVR are on after one's-complementing a zeroed register?

I have a code in assembly and I have to find out why the status flags are on

One of the codes is

LDI R16, 0
COM R16 

the result was 0xFF But I don’t understand why the S and C flags were on.

Upvotes: -1

Views: 257

Answers (3)

dvd280
dvd280

Reputation: 962

Why the c flag is set:

avr instruction datasheet states that 'COM Rn' is equivalent to '0xff-Rn'. It sets the C flag because of the way this insteuction is implemented in hardware (probably more space efficint to do it this way on the die).I programed avr's in assembly for years and never had an instance where it mattered. If you want to avoid it, you can either use 'clc' afterwards to clear it, or preload 0xff into another register and subtract Rn from it in code.

Why the S flag is set:

The S flag indicates whether ths most significant bit in the result is set. In your case, the result is 0xff which means the most significant bit is set. If you had loaded a number lower than 128 (0x80) and use 'COM' on it, you would have a cleared S flag.

Upvotes: 0

Peter Cordes
Peter Cordes

Reputation: 365457

COM isn't "complete", it's "one's complement" (bitwise inversion). Read the manual which explains how each instruction sets flags. One copy of the manual can be found at: https://courses.cs.washington.edu/courses/csep567/10wi/resources/ATmegaInstructionSet.pdf

It describes the "operation" as Rd ← $FF - Rd.
This is logically equivalent to bitwise NOT.

Some ISAs such as ARM have their carry flag as a not-borrow on subtract. (This matches the raw carry output from a binary adder-subtractor after doing subtraction as a + ~b with a carry-in of 1). If AVR was like that, com setting C=1 would be consistent with how sub would set it.

But AVR is not like that, C is a borrow flag (like x86, opposite of ARM). The documentation for BRLO confirms that: it jumps on C=1, because after a sub or cp, that means the left side was smaller. (i.e. there was a borrow from the highest bit.)


The documentation for how com actually sets status flags specifically says it always sets C to 1. So of course it always does that. It's a mystery to me why that was chosen,. though. Perhaps it was convenient for however they actually built their ALU to do bitwise NOT? eor doesn't affect C.

XOR with all-ones is a simple way to flip all the bits, and perhaps is what they do internally, regardless of the documentation describing it in terms of 2's complement / unsigned subtraction. Since AVR sets C opposite to the carry output from the ALU for some instructions (including sub), perhaps that's what's happening when the ALU is configured like for eor but with the carry-out being used. Just a guess about the internals; in terms of programming all you need to know is that com always sets C=1.

The N flag is set according to the result, V (signed overflow) is always cleared, and S = N^V is thus set according to the high bit of the register which in your case became 1.

Upvotes: 1

user29100520
user29100520

Reputation: 21

It is seems to be an AVR logical conflict. Instruction

SUB Rd,Rr. ; give C=1 when Rd<Rr

COM Rd ; operation like 0xff-Rd , this would give C=0. But actually the complement instruction always give C=1

Upvotes: 2

Related Questions