The bits of the result are obtained from the truncated sum of unsigned integers. The add instruction doesn't care about the sign here nor does it care about your own interpretation of the integers as signed or unsigned. It just adds as if the numbers were unsigned.
The carry flag (or borrow in case of subtraction) is that non-existent 9th bit from the addition of the 8-bit unsigned integers. Effectively, this flag signifies an overflow/underflow for add/sub of unsigned integers. Again, add doesn't care about the signs here at all, it just adds as if the numbers were unsigned.
Adding two negative 2's complement numbers will result in setting of the carry flag to 1, correct.
The overflow flag shows whether or not there's been an overflow/underflow for add/sub of signed integers. To set the overflow flag the instruction treats the numbers as signed (just like it treats them as unsigned for the carry flag and the 8 bits of the result).
The idea behind setting the overflow flag is simple. Suppose you sign-extend your 8-bit signed integers to 9 bits, that is, just copy the 7th bit to an extra, 8th bit. An overflow/underflow will occur if the 9-bit sum/difference of these 9-bit signed integers has different values in bits 7 and 8, meaning that the addition/subtraction has lost the result's sign in the 7th bit and used it for the result's magnitude, or, in other words, the 8 bits can't accommodate the sign bit and such a large magnitude.
Now, bit 7 of the result can differ from the imaginary sign bit 8 if and only if the carry into bit 7 and the carry into bit 8 (=carry out of bit 7) are different. That's because we start with the addends having bit 7=bit 8 and only different carry-ins into them can affect them in the result in different ways.
So overflow flag = carry-out flag XOR carry from bit 6 into bit 7.
Both my and your ways of calculating the overflow flag are correct. In fact, both are described in the Z80 CPU User's Manual in section "Z80 Status Indicator Flags".
Here's how you can emulate most of the ADC instruction in C, where you don't have direct access to the CPU's flags and can't take full advantage of the emulating CPU's ADC instruction:
#include <stdio.h>
#include <limits.h>
#if CHAR_BIT != 8
#error char expected to have exactly 8 bits.
#endif
typedef unsigned char uint8;
typedef signed char int8;
#define FLAGS_CY_SHIFT 0
#define FLAGS_OV_SHIFT 1
#define FLAGS_CY_MASK (1 << FLAGS_CY_SHIFT)
#define FLAGS_OV_MASK (1 << FLAGS_OV_SHIFT)
void Adc(uint8* acc, uint8 b, uint8* flags)
{
uint8 a = *acc;
uint8 carryIns;
uint8 carryOut;
// Calculate the carry-out depending on the carry-in and addends.
//
// carry-in = 0: carry-out = 1 IFF (a + b > 0xFF) or,
// equivalently, but avoiding overflow in C: (a > 0xFF - b).
//
// carry-in = 1: carry-out = 1 IFF (a + b + 1 > 0xFF) or,
// equivalently, (a + b >= 0xFF) or,
// equivalently, but avoiding overflow in C: (a >= 0xFF - b).
//
// Also calculate the sum bits.
if (*flags & FLAGS_CY_MASK)
{
carryOut = (a >= 0xFF - b);
*acc = a + b + 1;
}
else
{
carryOut = (a > 0xFF - b);
*acc = a + b;
}
#if 0
// Calculate the overflow by sign comparison.
carryIns = ((a ^ b) ^ 0x80) & 0x80;
if (carryIns) // if addend signs are the same
{
// overflow if the sum sign differs from the sign of either of addends
carryIns = ((*acc ^ a) & 0x80) != 0;
}
#else
// Calculate all carry-ins.
// Remembering that each bit of the sum =
// addend a's bit XOR addend b's bit XOR carry-in,
// we can work out all carry-ins from a, b and their sum.
carryIns = *acc ^ a ^ b;
// Calculate the overflow using the carry-out and
// most significant carry-in.
carryIns = (carryIns >> 7) ^ carryOut;
#endif
// Update flags.
*flags &= ~(FLAGS_CY_MASK | FLAGS_OV_MASK);
*flags |= (carryOut << FLAGS_CY_SHIFT) | (carryIns << FLAGS_OV_SHIFT);
}
void Sbb(uint8* acc, uint8 b, uint8* flags)
{
// a - b - c = a + ~b + 1 - c = a + ~b + !c
*flags ^= FLAGS_CY_MASK;
Adc(acc, ~b, flags);
*flags ^= FLAGS_CY_MASK;
}
const uint8 testData[] =
{
0,
1,
0x7F,
0x80,
0x81,
0xFF
};
int main(void)
{
unsigned aidx, bidx, c;
printf("ADC:\n");
for (c = 0; c <= 1; c++)
for (aidx = 0; aidx < sizeof(testData)/sizeof(testData[0]); aidx++)
for (bidx = 0; bidx < sizeof(testData)/sizeof(testData[0]); bidx++)
{
uint8 a = testData[aidx];
uint8 b = testData[bidx];
uint8 flags = c << FLAGS_CY_SHIFT;
printf("%3d(%4d) + %3d(%4d) + %u = ",
a, (int8)a, b, (int8)b, c);
Adc(&a, b, &flags);
printf("%3d(%4d) CY=%d OV=%d\n",
a, (int8)a, (flags & FLAGS_CY_MASK) != 0, (flags & FLAGS_OV_MASK) != 0);
}
printf("SBB:\n");
for (c = 0; c <= 1; c++)
for (aidx = 0; aidx < sizeof(testData)/sizeof(testData[0]); aidx++)
for (bidx = 0; bidx < sizeof(testData)/sizeof(testData[0]); bidx++)
{
uint8 a = testData[aidx];
uint8 b = testData[bidx];
uint8 flags = c << FLAGS_CY_SHIFT;
printf("%3d(%4d) - %3d(%4d) - %u = ",
a, (int8)a, b, (int8)b, c);
Sbb(&a, b, &flags);
printf("%3d(%4d) CY=%d OV=%d\n",
a, (int8)a, (flags & FLAGS_CY_MASK) != 0, (flags & FLAGS_OV_MASK) != 0);
}
return 0;
}
Output:
ADC:
0( 0) + 0( 0) + 0 = 0( 0) CY=0 OV=0
0( 0) + 1( 1) + 0 = 1( 1) CY=0 OV=0
0( 0) + 127( 127) + 0 = 127( 127) CY=0 OV=0
0( 0) + 128(-128) + 0 = 128(-128) CY=0 OV=0
0( 0) + 129(-127) + 0 = 129(-127) CY=0 OV=0
0( 0) + 255( -1) + 0 = 255( -1) CY=0 OV=0
1( 1) + 0( 0) + 0 = 1( 1) CY=0 OV=0
1( 1) + 1( 1) + 0 = 2( 2) CY=0 OV=0
1( 1) + 127( 127) + 0 = 128(-128) CY=0 OV=1
1( 1) + 128(-128) + 0 = 129(-127) CY=0 OV=0
1( 1) + 129(-127) + 0 = 130(-126) CY=0 OV=0
1( 1) + 255( -1) + 0 = 0( 0) CY=1 OV=0
127( 127) + 0( 0) + 0 = 127( 127) CY=0 OV=0
127( 127) + 1( 1) + 0 = 128(-128) CY=0 OV=1
127( 127) + 127( 127) + 0 = 254( -2) CY=0 OV=1
127( 127) + 128(-128) + 0 = 255( -1) CY=0 OV=0
127( 127) + 129(-127) + 0 = 0( 0) CY=1 OV=0
127( 127) + 255( -1) + 0 = 126( 126) CY=1 OV=0
128(-128) + 0( 0) + 0 = 128(-128) CY=0 OV=0
128(-128) + 1( 1) + 0 = 129(-127) CY=0 OV=0
128(-128) + 127( 127) + 0 = 255( -1) CY=0 OV=0
128(-128) + 128(-128) + 0 = 0( 0) CY=1 OV=1
128(-128) + 129(-127) + 0 = 1( 1) CY=1 OV=1
128(-128) + 255( -1) + 0 = 127( 127) CY=1 OV=1
129(-127) + 0( 0) + 0 = 129(-127) CY=0 OV=0
129(-127) + 1( 1) + 0 = 130(-126) CY=0 OV=0
129(-127) + 127( 127) + 0 = 0( 0) CY=1 OV=0
129(-127) + 128(-128) + 0 = 1( 1) CY=1 OV=1
129(-127) + 129(-127) + 0 = 2( 2) CY=1 OV=1
129(-127) + 255( -1) + 0 = 128(-128) CY=1 OV=0
255( -1) + 0( 0) + 0 = 255( -1) CY=0 OV=0
255( -1) + 1( 1) + 0 = 0( 0) CY=1 OV=0
255( -1) + 127( 127) + 0 = 126( 126) CY=1 OV=0
255( -1) + 128(-128) + 0 = 127( 127) CY=1 OV=1
255( -1) + 129(-127) + 0 = 128(-128) CY=1 OV=0
255( -1) + 255( -1) + 0 = 254( -2) CY=1 OV=0
0( 0) + 0( 0) + 1 = 1( 1) CY=0 OV=0
0( 0) + 1( 1) + 1 = 2( 2) CY=0 OV=0
0( 0) + 127( 127) + 1 = 128(-128) CY=0 OV=1
0( 0) + 128(-128) + 1 = 129(-127) CY=0 OV=0
0( 0) + 129(-127) + 1 = 130(-126) CY=0 OV=0
0( 0) + 255( -1) + 1 = 0( 0) CY=1 OV=0
1( 1) + 0( 0) + 1 = 2( 2) CY=0 OV=0
1( 1) + 1( 1) + 1 = 3( 3) CY=0 OV=0
1( 1) + 127( 127) + 1 = 129(-127) CY=0 OV=1
1( 1) + 128(-128) + 1 = 130(-126) CY=0 OV=0
1( 1) + 129(-127) + 1 = 131(-125) CY=0 OV=0
1( 1) + 255( -1) + 1 = 1( 1) CY=1 OV=0
127( 127) + 0( 0) + 1 = 128(-128) CY=0 OV=1
127( 127) + 1( 1) + 1 = 129(-127) CY=0 OV=1
127( 127) + 127( 127) + 1 = 255( -1) CY=0 OV=1
127( 127) + 128(-128) + 1 = 0( 0) CY=1 OV=0
127( 127) + 129(-127) + 1 = 1( 1) CY=1 OV=0
127( 127) + 255( -1) + 1 = 127( 127) CY=1 OV=0
128(-128) + 0( 0) + 1 = 129(-127) CY=0 OV=0
128(-128) + 1( 1) + 1 = 130(-126) CY=0 OV=0
128(-128) + 127( 127) + 1 = 0( 0) CY=1 OV=0
128(-128) + 128(-128) + 1 = 1( 1) CY=1 OV=1
128(-128) + 129(-127) + 1 = 2( 2) CY=1 OV=1
128(-128) + 255( -1) + 1 = 128(-128) CY=1 OV=0
129(-127) + 0( 0) + 1 = 130(-126) CY=0 OV=0
129(-127) + 1( 1) + 1 = 131(-125) CY=0 OV=0
129(-127) + 127( 127) + 1 = 1( 1) CY=1 OV=0
129(-127) + 128(-128) + 1 = 2( 2) CY=1 OV=1
129(-127) + 129(-127) + 1 = 3( 3) CY=1 OV=1
129(-127) + 255( -1) + 1 = 129(-127) CY=1 OV=0
255( -1) + 0( 0) + 1 = 0( 0) CY=1 OV=0
255( -1) + 1( 1) + 1 = 1( 1) CY=1 OV=0
255( -1) + 127( 127) + 1 = 127( 127) CY=1 OV=0
255( -1) + 128(-128) + 1 = 128(-128) CY=1 OV=0
255( -1) + 129(-127) + 1 = 129(-127) CY=1 OV=0
255( -1) + 255( -1) + 1 = 255( -1) CY=1 OV=0
SBB:
0( 0) - 0( 0) - 0 = 0( 0) CY=0 OV=0
0( 0) - 1( 1) - 0 = 255( -1) CY=1 OV=0
0( 0) - 127( 127) - 0 = 129(-127) CY=1 OV=0
0( 0) - 128(-128) - 0 = 128(-128) CY=1 OV=1
0( 0) - 129(-127) - 0 = 127( 127) CY=1 OV=0
0( 0) - 255( -1) - 0 = 1( 1) CY=1 OV=0
1( 1) - 0( 0) - 0 = 1( 1) CY=0 OV=0
1( 1) - 1( 1) - 0 = 0( 0) CY=0 OV=0
1( 1) - 127( 127) - 0 = 130(-126) CY=1 OV=0
1( 1) - 128(-128) - 0 = 129(-127) CY=1 OV=1
1( 1) - 129(-127) - 0 = 128(-128) CY=1 OV=1
1( 1) - 255( -1) - 0 = 2( 2) CY=1 OV=0
127( 127) - 0( 0) - 0 = 127( 127) CY=0 OV=0
127( 127) - 1( 1) - 0 = 126( 126) CY=0 OV=0
127( 127) - 127( 127) - 0 = 0( 0) CY=0 OV=0
127( 127) - 128(-128) - 0 = 255( -1) CY=1 OV=1
127( 127) - 129(-127) - 0 = 254( -2) CY=1 OV=1
127( 127) - 255( -1) - 0 = 128(-128) CY=1 OV=1
128(-128) - 0( 0) - 0 = 128(-128) CY=0 OV=0
128(-128) - 1( 1) - 0 = 127( 127) CY=0 OV=1
128(-128) - 127( 127) - 0 = 1( 1) CY=0 OV=1
128(-128) - 128(-128) - 0 = 0( 0) CY=0 OV=0
128(-128) - 129(-127) - 0 = 255( -1) CY=1 OV=0
128(-128) - 255( -1) - 0 = 129(-127) CY=1 OV=0
129(-127) - 0( 0) - 0 = 129(-127) CY=0 OV=0
129(-127) - 1( 1) - 0 = 128(-128) CY=0 OV=0
129(-127) - 127( 127) - 0 = 2( 2) CY=0 OV=1
129(-127) - 128(-128) - 0 = 1( 1) CY=0 OV=0
129(-127) - 129(-127) - 0 = 0( 0) CY=0 OV=0
129(-127) - 255( -1) - 0 = 130(-126) CY=1 OV=0
255( -1) - 0( 0) - 0 = 255( -1) CY=0 OV=0
255( -1) - 1( 1) - 0 = 254( -2) CY=0 OV=0
255( -1) - 127( 127) - 0 = 128(-128) CY=0 OV=0
255( -1) - 128(-128) - 0 = 127( 127) CY=0 OV=0
255( -1) - 129(-127) - 0 = 126( 126) CY=0 OV=0
255( -1) - 255( -1) - 0 = 0( 0) CY=0 OV=0
0( 0) - 0( 0) - 1 = 255( -1) CY=1 OV=0
0( 0) - 1( 1) - 1 = 254( -2) CY=1 OV=0
0( 0) - 127( 127) - 1 = 128(-128) CY=1 OV=0
0( 0) - 128(-128) - 1 = 127( 127) CY=1 OV=0
0( 0) - 129(-127) - 1 = 126( 126) CY=1 OV=0
0( 0) - 255( -1) - 1 = 0( 0) CY=1 OV=0
1( 1) - 0( 0) - 1 = 0( 0) CY=0 OV=0
1( 1) - 1( 1) - 1 = 255( -1) CY=1 OV=0
1( 1) - 127( 127) - 1 = 129(-127) CY=1 OV=0
1( 1) - 128(-128) - 1 = 128(-128) CY=1 OV=1
1( 1) - 129(-127) - 1 = 127( 127) CY=1 OV=0
1( 1) - 255( -1) - 1 = 1( 1) CY=1 OV=0
127( 127) - 0( 0) - 1 = 126( 126) CY=0 OV=0
127( 127) - 1( 1) - 1 = 125( 125) CY=0 OV=0
127( 127) - 127( 127) - 1 = 255( -1) CY=1 OV=0
127( 127) - 128(-128) - 1 = 254( -2) CY=1 OV=1
127( 127) - 129(-127) - 1 = 253( -3) CY=1 OV=1
127( 127) - 255( -1) - 1 = 127( 127) CY=1 OV=0
128(-128) - 0( 0) - 1 = 127( 127) CY=0 OV=1
128(-128) - 1( 1) - 1 = 126( 126) CY=0 OV=1
128(-128) - 127( 127) - 1 = 0( 0) CY=0 OV=1
128(-128) - 128(-128) - 1 = 255( -1) CY=1 OV=0
128(-128) - 129(-127) - 1 = 254( -2) CY=1 OV=0
128(-128) - 255( -1) - 1 = 128(-128) CY=1 OV=0
129(-127) - 0( 0) - 1 = 128(-128) CY=0 OV=0
129(-127) - 1( 1) - 1 = 127( 127) CY=0 OV=1
129(-127) - 127( 127) - 1 = 1( 1) CY=0 OV=1
129(-127) - 128(-128) - 1 = 0( 0) CY=0 OV=0
129(-127) - 129(-127) - 1 = 255( -1) CY=1 OV=0
129(-127) - 255( -1) - 1 = 129(-127) CY=1 OV=0
255( -1) - 0( 0) - 1 = 254( -2) CY=0 OV=0
255( -1) - 1( 1) - 1 = 253( -3) CY=0 OV=0
255( -1) - 127( 127) - 1 = 127( 127) CY=0 OV=1
255( -1) - 128(-128) - 1 = 126( 126) CY=0 OV=0
255( -1) - 129(-127) - 1 = 125( 125) CY=0 OV=0
255( -1) - 255( -1) - 1 = 255( -1) CY=1 OV=0
You can change #if 0
to #if 1
to use the sign-comparison-based method for overflow calculation. The result will be the same. At first glance it's a bit surprising that the sign-based method takes care of the carry-in too.
Please note that by using my method in which I calculate all carry-ins into bits 0 through 7, you also get for free the value of the half-carry
flag (carry from bit 3 to bit 4) that's needed for the DAA
instruction.
EDIT: I've added a function for subtraction with borrow (SBC/SBB instruction) and results for it.