Reputation: 11
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
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
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
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