To put it in the simplest terms possible, V means that the N flag is wrong -- an addition has gone outside the range 0 to 127, or a subtraction has gone outside the range -128 to -1, and so caused a false change of sign.
This happens whenever an ADC instruction with a positive addend already in the accumulator and a positive augend specified in the instruction produces a negative-looking sum (when it's actually between 128 and 255); or an SBC instruction with a negative minuend already in the accumulator and a positive subtrahend being taken away from it produces a positive-looking difference (actually between -256 and -129). Subsequent arithmetic operations may push it back into range, of course, and the way twos-complement arithmetic works will mean the answer is then right (they may just as easily make it wronger and wronger; even eventually going past -256 or +255, where things begin to look right again until we exceed -384 or +383 .....) but right now, the important thing we need to know is: if V is set following an addition or subtraction, N is wrong. V=1 and N=1 together indicate a positive number; V=1 and N=0 indicate a negative number. If V=0 then we do not have to worry, of course: N is correct.
(Part of my day job involves testing edge cases. And the V flag is a nice example of an edge case test, right there in the 6502 hardware.)
For all but the most significant byte of a multi-byte quantity, V is as meaningless as N (which is set from the high bit of the last byte seen, but is only the sign bit when it's the very highest bit, i.e., in the highest byte.)
In the case of higher-or-lower comparisons between signed numbers, this is important. CMP performs an unsigned comparison without borrow, and sets C if the subtrahend is smaller than or equal to the minuend and Z if it is equal. That's fine for unsigned numbers. But -128 (which looks like 128) appears larger than 127, and -1 (which looks like 255) appears larger than 1. In fact, all simple comparisons between negative and positive numbers fail this way.
If we add 128 to the negative numbers -128 to -1 (giving a range 0 to 127 instead of -128 to -1) and subtract 128 from the positive numbers 0 to 127 (giving a range -128 to -1, which looks like 128 to 255, instead of 0 to 127) the two ends of the range effectively swap places, putting the whole number line into the right-looking order for the CMP instruction. And that operation is basically just toggling bit 7 of each of the minuend (comparand?) and subtrahend (comparator?), which can be done with EOR #&80.
For multi-byte signed numbers, we can't really use CMP because it doesn't allow for importing a borrow. So instead we will have to do a multi-byte subtraction, starting with SEC and then LDA / SBC pairs. And this is where we are likely to run afoul of sign bit issues.
Here's an example from BCP, of course:
Code: Select all
\ Test whether the point is off to the left (bottom) of the box \ Y=0 for left, Y=2 for bottom .testLB SEC LDA (ptb),Y \ point base SBC (bxb),Y \ box base INY LDA (ptb),Y SBC (bxb),Y \ now if V is set, N will be wrong BVC testLB1 EOR #&80 \ flip bit 7 .testLB1 \...
Anyway, now you know what V does. Well, almost. Because there is another instruction, besides ADC and SBC, which can affect it: BIT. BIT is limited to absolute addressing (though it has "long" and "short" forms) and performs an AND operation between the contents of the accumulator and the contents of the address supplied in the operand; the result is discarded, but the Z flag is set if all bits of the result were zero. It also sets N and V to bits 7 and 6 respectively of the address contents before the AND -- this enables you to test a flag in either bit 6 or bit 7 of a byte without wasting cycles and without disturbing the contents of the accumulator.
You can test the V flag and conditionally branch with BVC and BVS; and you can clear it with CLV. (If you ever need some code to be able to run independently of its position in memory, CLV followed by BVC will simulate an unconditional relative branch without affecting N, Z or C.) There's no SEV instruction; but if you ever need to set the V flag, you can do it with a BIT instruction pointing to an address which you know contains a value with bit 6 set -- an RTS instruction in your code is as good as anything. Other instructions that can affect V are PLP, RTI and there is also an input pin on the processor to allow it to be set by hardware.
And that's about it for V.