Search code examples
assemblyxormicroprocessorsz80

How does XORing the A register clear the carry bit on the F register in the Z80?


I'm reading a book about the Zilog Z80 processor, in which whenever the author wants to clear the carry bit for a possible reason he does any of the following:

XOR A
AND A
OR  A

How does that affect the C bit which is in the F register? In other words, how does performing an operation on some register (A) affects another register (F)?


Solution

  • I think I understand your concern. The flags register gets the result of an operation so it makes sense that AND, OR, XOR all affect the Zero flag, Sign flag and Parity flag. Those are all direct properties of the result. But the operations are not arithmetic so Carry isn't a natural property.

    I think the answer lies in the ALU itself. As programmers we view the ALU as a multi-function box. You give it a value and an operation and it performs that operation on the accumulator setting flags as a byproduct. Internally we suspect it has a separate circuit for each operation: add, subtract, and, or, xor.

    In actual fact it is more like a multi-purpose function of each bit that can be modified to perform the desired operations. At a high level we can see this with add vs add with carry. Internally the only difference in those instructions is whether or not the carry flag is used in performing the add. Similarly, subtract is nothing but adding the two's complement of the number. So subtract only has some front-end change of an operand and uses the same add circuit.

    Now consider how we do an addition on a single bit. Ignoring the carry, notice that 0+0 = 0, 0+1 = 1+0 = 1 and 1+1 = 0. And what about carry? carry(0+0) = carry(0+1) = carry(1+0) = 0 and carry(1+1) = 1.

    Recognize those functions? The carry of two bits is their AND. The result of the two bits added is their XOR. If you extend this idea a bit more you can see how a simple circuit can add two bits together with a carry input and produce the resulting bit and a carry output. Chain 8 of them together and you're adding numbers.

    If you were designing a processor you might also notice that you can get XOR almost for free. XOR is just adding two numbers together but stopping the carry going from bit to bit. Similar shortcuts can pull the AND value out you normally get from the carry calculation and I'm sure there's some other trick to find OR in there. The details get pretty important here because the designers of the Z-80 were not using AND and XOR gates but raw transistor logic which is even more flexible in what it can produce from a circuit.

    Anyhow, now there's a choice. Our XOR is zeroing the carry between each bit. What about the 8th bit? Well, offhand we should zero it as well. Otherwise the carry bit will be the AND of the sign bits which just seems like it will confuse and annoy assembler programmers and not be of much use. But if we zero that carry bit like we did all the others then we have a nice, symmetric circuit and the result is clear and unambiguous. And, I suspect, it is easier to zero the value than it is to ignore it.

    So, letting the zero carry come through saves us a few transistors. And that side effect comes in handy in an operations like "OR A,A" or "AND A,A" which otherwise doesn't do a whole lot. Now, the Z-80 inherited this behavior from the 8080 so it was really the 8080 designer's choice not the Z-80. You can see they thought about it in the instruction set as they only gave us two operations to directly affect the carry: SCF - set carry flag to 1 and CCF - complement the carry flag. They explicitly avoided giving us a "clear carry flag" since "OR A,A" already does that for free. Thus the whole business saves an entire instruction. And, we can only suppose, they reasoned that zeroing the carry flag on a logical operation isn't much of an impediment to programming. In most cases you're either doing a logical calculation or an arithmetic one so logical operations zapping carry isn't a big deal. Clearly other CPU designers didn't agree but it's a fair choice.

    Bottom line: clearing the carry is a natural outcome of the circuitry which the 8080 designers decided was a useful side-effect to keep and chose to let it be rather than add circuitry to suppress it.

    For specific detail, see how the Z-80 ALU operates internally and the 8085 ALU internals.