How to determine when zero flag, sign flag, overflow flag and carry flag are set?
Asked Answered
G

2

12

The whole flag thing is confusing the heck out of me. The definitions on the web seem really plain. I can't seem to get a really good applicable explanation to all this.

According to their definitions, - carry: indicates an unsigned integer overflow - overflow: indicates a signed integer overflow - zero: an operation produced zero - sign: operation produced a negative number

So how in the world are the following sentences true? - The following instructions will set the Sign flag: (The answer here is 252 not a negative number. So why is the sign flag set?)

mov al,0FEh
sub al,2
  • Adding 7Fh and 05h in an 8-bit register sets the Overflow flag.(The answer here is 132. It’s not above 255 so why is there an overflow?)

  • Adding 0FFh and 05h in an 8-bit register does not set the Overflow flag.(the answer is 300 so how is there not an overflow flag on? It’s above 256)

  • Adding 5 to 0FBh in an 8-bit register sets the Zero flag (The answer here is 256, not 0. I understand the 8 bit can only hold 255 but where does the “0” come from? I just don’t get it.)

Can someone please let me know what I'm doing wrong here and what the correct way to approach this is? Thanks.

Gristmill answered 12/4, 2016 at 20:29 Comment(6)
You might want to read about how negative numbers are represented in two's complement.Aplite
"The answer here is 252 not a negative number" The answer is 0xFC which can be viewed either as 252 or -4. The desciption of the sign flag in Intel's manual is "Set equal to the most-significant bit of the result, which is the sign bit of a signed integer. (0 indicates a positive value and 1 indicates a negative value.)". 0xFC clearly has the most significant bit set.Dreary
"I understand the 8 bit can only hold 255 but where does the “0” come from?" What is the value of the 8 least significant bits of 256?Dreary
@Dreary 0. Does that mean that the zero flag is really turned on when the value of the 8 least significant bit is 0, and not just "when an operation produces 0"?Gristmill
This SO answer might help understand. It is 4 bits, but it applies equally well for wider register like 8,16,32,64 etc: https://mcmap.net/q/427156/-sign-carry-and-overflow-flag-assemblyWadai
Adding 0xFF (=255) to 0x05 (=5) is not equal to 300, but 260Marking
B
10

The answer here is 252 not a negative number. So why is the sign flag set?

As unsigned it is 252, but unsigned can't have a sign, so the sign flag is only related to number handled as signed. It doesn't matter how you handle it, the processor always handles it as signed with the sign flag. So 252 is over 127, therefore it is negative in 2's complement and the sign bit is set.

Adding 7Fh and 05h in an 8-bit register sets the Overflow flag.(The answer here is 132. It’s not above 255 so why is there an overflow?)

As you said, overflow is set when a signed number would overflow. A signed 8bit variable can go from -128 to 127. Therefore going from 127 to 132 is an overflow.

Adding 0FFh and 05h in an 8-bit register does not set the Overflow flag.(the answer is 300 so how is there not an overflow flag on? It’s above 256)

Again, overflow is signed overflow. This causes an unsigned overflow, so the carry bit will be set.

Adding 5 to 0FBh in an 8-bit register sets the Zero flag (The answer here is 256, not 0. I understand the 8 bit can only hold 255 but where does the “0” come from? I just don’t get it.)

As you said, 8 bits can go up to 255. After that it overflows and the lowest 8 bits are 0. So the result is zero and the zero bit is set.

Bowen answered 12/4, 2016 at 20:37 Comment(1)
Thank you so much! My brain is shutting down from trying to figure this out but your answers are making a lot more sense. I will need to take a break and process/ practice this more. Thanks again!Gristmill
L
2

Another excellent guide: Understanding Carry vs. Overflow conditions/flags . It has some nice step-by-step examples with 4-bit numbers that make it easy to keep the whole thing in your head. It also explains that unsigned carry is what you're checking for when interpreting the bits as unsigned, while signed overflow is what you're checking for when interpreting the bits as signed.


Based on OP's comment:

Does that mean that the zero flag is really turned on when the value of the 8 least significant bit is 0, and not just "when an operation produces 0"

The key thing you need to remember is that this is fixed-width integer arithmetic. In an 8bit register, 0xFF + 1 really does produce a 0.

In mathematical terms, this is modular arithmetic, with a modulus of 28 for an 8bit operation.

So yes, ZF is set according to dst = (dst+src) % 0x100.

It's designed this way because usually you just want to know whether the register is zero, whether you're counting up towards zero with inc on a register that started out negative, or whether you're counting down towards zero with a register that started positive.

You can still check CF==0 and ZF==1 to detect the case when you got a zero without carry. If ZF was only set when dst and CF were both zero, you'd often need another instruction to just test the result register.


Having CF and ZF independent mean that the unsigned condition codes after a cmp or sub work like this:

JA      Jump if above (CF=0 and ZF=0).
JAE     Jump if above or equal (CF=0).
JB      Jump if below (CF=1).
JBE     Jump if below or equal (CF=1 or ZF=1).

JC      Jump if carry (CF=1).

JE      Jump if equal (ZF=1).

I think if ZF could only be set when there wasn't a carry, you couldn't tell the difference between Above and Above-or-Equal. So that's probably the most concrete reason for the design decision to not be made the way your first guess was going.

Here's one of the signed compare conditions:

JLE     Jump  if less or equal (ZF=1 or SF ≠ OF).

The full set of conditions is in Intel's insn set reference manual (links in the tag wiki), under the jcc (jump if condition code) instruction listing.

Loudmouthed answered 12/4, 2016 at 22:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.