37

The 6502 has a group of opcodes which copy bit 5 from the opcode into one of the status flags.

(I know it's not implemented this way, but it looks as though the bit fields are: 2 bits to select the flag out of CIVD, one bit to clear or set, followed by 11000).

See:

0001 1000   CLC    Clear carry
0011 1000   SEC    Set carry
0101 1000   CLI    Clear interrupt flag
0111 1000   SEI    Set interrupt flag
1001 1000   CLV    Clear overflow flag
1011 1000   TAY    Transfer A to Y
1101 1000   CLD    Clear decimal flag
1111 1000   SED    Set decimal flag

The blatant odd one out here is TAY, which takes the place of what looks like should be SEV. SEV does not exist, but intuitively is exactly as useful as CLV, and very easy to implement.

On the other hand, the group of instructions TAY, TYA, TAX, TXA are not really laid out regularly enough that I see any motive for "overriding" a what could've been SEV.

What happened?

  • The fact that there's a direct pin that can set the overflow flag is definitely a bit of a "i guess someone somewhere had a use case that needed it". The use of it in the 1540/1541(and I'd guess 1570/1571?) is really fascinating, I don't know if I ever heard of another real-world use of the pin. – Joe Oct 14 at 23:30
  • 1
    @Joe I suspect that it wasn't "someone already asked for this" but just really good design; I go into more detail in my answer below. – Curt J. Sampson Oct 15 at 2:28
  • 2
    @Joe Having direct testable pins was quite common on CPUs. Many had one or more as part of the flag register, while others had fast implied checks combining pin test and branch. – Raffzahn Oct 15 at 12:38
  • a fascinating insight into how the 6502 was put together is : youtube.com/watch?v=fWqBmmPQP40, and the (related) visual6502.org website (you can play with it : visual6502.org/JSSim/index.html) . I would ask those persons that question, if I were you – Olivier Dulac Oct 16 at 11:50
  • 1
    @OlivierDulac you would actually discourage people from asking questions on this platform? Better take that to Meta. – Wilson Oct 16 at 11:59
22

There is simply no need for setting Overflow. The same is as well true for Negative/Sign and Zero. No operation will be influenced by any of them, it's only used to signal an overflow during ADC and SBC (well, and BIT for testing bit#6).

In fact, the question is rather, why there is a CLV present, as there is no reason, within the boundaries of the instruction set, to set or clear V at all (*1). Any of the three V changing instructions will always set/reset it without looking at the former state (*2). Looking at the various transfer instruction it seams rather that TAY ist out of order.

The need to add CLV becomes obvious when considering that hardware can set V via the SO (Set Overflow) input pin.

The combination of SO input and the BVC instruction creates the shortest possible timing to react for an external signal. Having BVC loop on itself will reduce reaction time to a maximum of 3 cycle.

L1  BVC  L1

Way shorter than any IO test or interrupt handling. In fact, the overhead is zero (compared to more than 13 clocks with an interrupt (*3)) and all response time is reduced to 'instruction jitter' i.e. the time needed before either condition can be detected and the instruction stream is redirected. With an interrupt the actual instruction always needs to finish, which may take anywhere between 1 and 6 cycles. (*4)

Since this can only work as intended if V is cleared before entering the loop, software needs a way to do so. That's why CLV got added.


Why V was choosen:

The reason why V has been used is simply that of the non-modal flags (*5), C, N and Z are changed with next to any data manipulating instruction, while V is only influenced by BIT, ADC and SBC. By using V, it is still possible to write meaningful programs that check for an external events while doing other tasks, essentially allowing synchronous event detection with the least possible effort.

Any generic IO-Test would require at least a BIT instruction (if the bit to test is #6 or #7) and a follow up branch, resulting in at least 5/6 cycles and 4 bytes used. If not placed that nice, it'll needs loading and testing a value, which not only needs more cycles and program bytes, but as well destroys a register as well, serious reducing usefulness. With SO and BVS detection can be inserted as often as needed by spending just two bytes and two cycles (in case of not set) each.


Background: Other CPUs

While the V/SO combination is quite restricted and seams more like added on afterthought, having direct testable CPU pins was quite common. Basically two types were used:

  • Reflecting the state in one or more Flag bits or

  • Offering fast checks, either

    • By moving them to flags by a single byte instruction, or

    • By offering a combined check and branch instruction for these pins.

In any variation the goal was to allow a few (usually 1..4) input pins to be checked with as least instructions and as fast as possible.

In addition some had as well similar fast output pins.

Some Examples:

  • Intel 8085 - RIM/SIM instruction to read SID and control SOD
  • Valvo/Signetics 2650 - Two bits (#6/7) in upper status register (PSU) with #6 controlling an output pin (Flag) and #7 reflecting the (Sense) input pin.
  • Valvo/Signetics 2650 - As well as direkt I/O instructions (WRTC/WRTD;REDC/REDD) for two implied addressed ports (called Command/Data).
  • Fairchild F-8 - Had two 8 bit ports on chip (*6), operated by special short INS/OUTS instructions.
  • National SC/MP - Maxes the Flag-in-Status-Register concept with two input bits (Sense A/B) and 3 output (Flag 0/1/2)
  • RCA/Intersil CDP1802 - Offering a single output (Q) set/reset by SEQ/REQ and four inputs (EF1/2/3/4). The Inputs are not visible in any status register (the 1802 doesn't have one) but direct testable by a separate set of branch instructions (B1..B4/BN1..BN4)
  • General Instruments CP1600 - Maxing out the testable input lines to 16 by having a special branch instruction (BEXT- Branch on EXTernal condition) which outputs a 4 bit address on EBCA0..4 and reads the addressed bit via EBCI.

*1 - Likewise for N and Z.

*2 - Unlike the related Carry flag, which needs not only to be checked, but also cleared or set before doing an ADC or SBC

*3 - 7 for the interrupt itself plus 6 for RTI -being an interrupt it as well preservation of registers will usually be needed, weras done via BVC (as wait or inline) will already have all registers set as they need to be and no need to restore.

*4 - Not 7, as an instruction only needs to finish when already started :)

*5 - Modal flags are such that change CPU operation, like the Decimal or Interrupt Disable

*6 - No, despite its odd style, it's not a microcontroller

  • 4
    +1 for reframing the question correctly " the question is rather, why there is a CLV" – JeremyP Oct 15 at 8:53
  • 2
    Regarding your fourth footnote: There is an undocumented instruction that's 8 cycles long; this would actually mean a 7 cycle maximum interrupt latency. – Wilson Oct 17 at 14:07
  • @Wilson: A fair number of them. All six read-modify-write functions have variants that also perform an operation on the accumulator, and those variants all support eight-cycle (zp,X) and (zp),y addressing modes. – supercat Oct 17 at 15:00
  • @Wilson Bug-using should not be considered part of any game :) – Raffzahn Oct 18 at 9:45
44

Setting and clearing carry, the decimal or interrupt flags is useful:

  • the carry flag because the 6502 offers only add and subtract with carry;
  • the decimal flag because it changes the mode of the processor; and
  • the interrupt flag because it masks or unmasks the maskable interrupt.

Conversely, explicitly setting and clearing the other flags mostly isn't useful — that's unambiguously true of the negative, zero and break flags. So the more helpful question is: why allow overflow to be cleared, rather than ignoring it completely like negative et al?

The answer is that the 6502 has a specific input pin, SO, which can be used by external hardware to set the overflow flag. The intention is low-latency hardware interfacing — the programmer enters a spin loop like:

       CLV
.here: BVC .here

The worst-case latency there (assuming no page jump) is three cycles — after two cycles the entire BVC has been read and the decision is made to branch, the overflow flag is set but just too late, an extra cycle is spent performing the branch and then two more rereading the BVC. That's substantially faster than even the fastest IRQ, which starts at 7 cycles.

The main example of usage I'm aware of is the C1540/1541 disk drive where overflow can be enabled to be set each time the flux transition shift register is full.

  • 1
    It seems in this case it's more the jitter (i.e. window in which the CPU can react) than the lattency (time until CPU reacts) which matters. The jittering is minimzed to 3 cycles instead of at least 7 cycles for other kind of loops involving non-page-zero-memory-mapped IOs, as well as 7 cycles for interupts. If the interupted code is a long chain of NOPs however the jitter is also 2 cycles. Instead of CLV, a WAI instruction would have been preferable, and reduced the jitter to 1 cycle, a.k.a no jitter at all. But that's not what they picked. – Bregalad Oct 15 at 14:44
  • @Bregalad: Having a wide range of eight opcodes that would all behave as "branch if input set" and eight "branch if input clear" would have made it possible for a 6502 system to test up to 8 inputs using single instructions using an 8-input multiplexer with the select inputs tied to three data-bus pins. I don't know if any processors took such an approach, but the 6502 has a sufficiently large undecoded regions of opcode space that such a thing could have been pretty easy. – supercat Oct 15 at 15:35
  • 2
    @Tommy Erm, as I read his comment, he is point is in favour of the SO/BVC solution because of having a lower jitter than using INT, which has a 1..6 cycle jitter (he said 7) depending on the instruction during wich execution the interrupt occurs. The main argument is only about the jitter of an interrupt acceptance, not the additional overhead (which makes, as you mention, interrupts even less usable). – Raffzahn Oct 15 at 22:01
  • 1
    @Raffzahn you are a better reader than I. – Tommy Oct 15 at 22:28
  • 1
    Given a decoded I/O address, adding one chip to a 6502 system will allow it to wait for a signal with zero cycles of jitter at no cost beyond the store. The Atari 2600, which came out in 1977, demonstrates this technique. – supercat Oct 16 at 16:11
7

Here are a few further thoughts on the setting of flags and the SO (set overflow) pin mentioned in the other answers, in response to Joe's comment,

The fact that there's a direct pin that can set the overflow flag is definitely a bit of a "i guess someone somewhere had a use case that needed it". The use of it in the 1540/1541(and I'd guess 1570/1571?) is really fascinating, I don't know if I ever heard of another real-world use of the pin.

I wouldn't be surprised if there were no specific use case at the time and this were just another example of Chuck Peddle's great design skills.

Fast response to external signals was clearly a design goal of the 6502. Note, for example, how unlike the 6800 it stacks only the minimum number of registers when responding to an IRQ. (The 6809 later copied this with its additional "Fast IRQ.") And then there was the BIT instruction, setting not one but two¹ flags directly from memory (read: I/O ports), and various other instructions that directly twiddled memory without needing to touch registers, also saving cycles when doing I/O.

But one thing that Peddle needed was to be able to compete with the 6800's WAI instruction, which basically "pre-executed" the initial part of the interrupt response (immediately stacking the registers and loading the PC with the address in the IRQ vector) and waited for the interrupt, allowing it to start executing the interrupt code with no latency.

I don't know how expensive that would have been to implement (the 6502 was, if anything, even more focused on being cheap than fast), but that technique also had a major issue: once the response was complete, there was significant time until the next response could be generated because the CPU would still have to go through the whole RTI/WAI or RTI/INT sequence before the interrupt code could be executed again. Peddle's solution avoided this by not using an interrupt at all but instead a spin loop. This increased the latency in response to the external signal by up to three cycles, but meant that when processing of the signal was completed, one could be ready to respond to the next instance of that signal much faster than the 6800 could, increasing the maximum signal frequency that the 6502 could handle.

Setting flags to branch based on the state of a chip pin was not a technique original to Peddle; the RCA COSMAC 1801 processor, released in early 1975 as the 6502 design was being worked on, had "four I/O flag inputs directly testable by branch instructions." (You can see more about how this works on the RCA 1802, which was basically just a single-chip version of the two-package 1801.)


¹The N (negative) and V (overflow) flags are copied directly from bits 7 and 6 of the memory location tested. Additionally, the Z (zero) flag is also updated based on the AND of the A register and the memory value; this may or may not be useful and/or a time saver depending on what's currently in the A register at the time you do the test.

  • The 6502 could have processed I/O much more effectively if opcodes of the form xxxxx111 were NOP, xxxx0011 were "branch if input low", and xxxx0011 were "branch if input high". Adding a 74HC138 and some 8-bit addressable latches and 8-bit multiplexers would have made it easy to interface to up to 32 inputs or outputs with very fast I/O instructions. – supercat Oct 15 at 2:54
  • 2
    "there was the BIT instruction, setting not one but two flags directly from memory" -- actually up to THREE flags. bit7 of memory goes to N, bit6 to V, and still the result of ANDing A with memory sets Z. – lvd Oct 15 at 12:30
  • 1
    @lvd Thanks for pointing that out! I've updated the answer with a footnote about this. However, the Z flag doesn't really fall under what I was trying to communicate with "direct" in that it needs other setup, and possibly register saving or unwanted register value destrcution, to set the test value. – Curt J. Sampson Oct 16 at 2:06
  • @CurtJ.Sampson Some nitpicking on the footnote: Overflow is noted as V thruout all 6500 documentation. – Raffzahn Oct 16 at 11:42
  • @Raffzahn Good nitpick: I have fixed the post. Thanks. Now, of course, I have a nitpick with the MOS for calling the pin SO instead of SV.... – Curt J. Sampson Oct 16 at 15:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.