The overflow flag indicates that the sign of the number has changed incorrectly. So there is overflow if you add two positive numbers and get a negative result. There is also overflow if you add two negative numbers and get a positive result.
You cannot overflow when adding two numbers of different characters, because the range does not allow this. The smallest positive plus the largest negative is 0 + (-128), which fits perfectly - 0 plus everything that fits in 8 bits will obviously go in 8 bits. The smallest negative plus the largest positive is -1 + 127 = 126. What works.
(EDIT: and even with hyphenation, 0 + -128 + 1 = -127, which fits, and -1 + 127 + 1 = 127, which fits)
Thus, overflow occurs if two inputs with the same icon produce a result with a different sign. Otherwise, this is understandable.
You can express it as just a bitwise operation on the bits of a sign. Suppose you have + b = c.
a ^ b
will have 1 in the sign if the signs were different. You want to know the opposite. So:
~(a ^ b)
gives a 1 in the sign if the signs were the same. This is the first part of the test. Assuming a and b have the same sign, you can check c against any of them. This time you want to check the difference, just to:
a ^ c
You need the checked bit to be set in both parts of the test, so you can combine those that have binary code (and leave a lot of brackets to refer to verbal reasoning):
(~(a ^ b))&(a ^ c)
You only need a sign bit, so cancel this:
(~(a ^ b))&(a ^ c)&0x80
This will evaluate to 0x00 if the overflow flag should be clear and 0x80 if it should be set. So just slide this place.
(aside: although many instructions set flags on 6502, and only one provides a status register, so emulators often store flags separately in any convenient form and make up a status register on demand, in which case you won’t worry about offset and layout, you just save this result)