I understand the use of the carry and overflow flags exist for error checking in arithmetic, but why is the zero flag useful to the system/programmer?
CodePudding user response:
An extremely common task for any computer is to compare two integers (or pointers) for being greater / less / equal, and conditionally jump according to the result. This is how you implement higher-level constructs like if (x < y)
, if (x == y)
, and so on.
On x86, as in many other architectures, this task is broken into two instructions: CMP
or some similar instruction to perform the arithmetic of the comparison, and the conditional Jcc
instructions to perform the jump. There has to be some kind of state in the CPU for CMP
to communicate its result for Jcc
to use, and that's what the FLAGS
register is for.
A test for equality is the most basic of these, so it makes sense that there should be a flag which is set according to whether the two operands of CMP
were equal. Since CMP
is really a subtraction operation under the hood, this is equivalent to asking whether the result of the subtraction was zero, which is easily done in hardware by OR'ing together all the bits and inverting the one-bit result. And that's the zero flag. Since it costs basically nothing, the 8086 designers decided to set the zero flag in this way after almost every arithmetic or logical instruction, not only CMP
.
Then "jump if equal" is equivalent to "jump if zero flag set". Indeed, JE
and JZ
are just different assembly mnemonics for the same machine-code instruction.
The other standard arithmetic flags (carry, sign, overflow) are also used in this way. This is by far a more common use for them than any kind of error checking. (Indeed, many compiled languages do no such error checking and simply ignore overflow if it occurs.) For instance, if you want to jump if AX < BX
, where the values in the registers are to be treated as unsigned, you would subtract BX from AX and jump if a borrow occurred, which on x86 sets the carry flag. Then your code simply looks like CMP AX, BX / JC label
. The assembler lets you use JB
instead of JC
so that you can think of it as "jump if below". You can also combine it with the zero flag; if you want to jump if AX <= BX
, then you write CMP AX, BX ; JBE label
, where JBE
will jump if either of the carry or zero flags is set.
The sign and overflow flags are used similarly for signed compares, though the rules are a little more complicated.