Page 1 of 1

Re: interupts

Posted: Sat May 11, 2013 5:11 am
by Dr Jefyll
Welcome Gadersd! Do you intend to build actual hardware or are you creating simulation software that'll run on a host CPU?

Interrupts are less complex than you might suppose. If you already understand how a 6502 fetches and executes instructions from memory, that covers a lot of what you need to know. Executing an interrupt is simply a variation on the process of executing an instruction fetched from memory. In fact, it may help to think of an interrupt as an instruction not fetched from memory. It is triggered by the IRQ or NMI input instead. (RESET operates similarly.)

The normal fetch-execute process for 6502 is basically this:
  • wait until the currently-executing instruction is (almost*) complete.
  • Use the Program Counter to drive the address bus and thus fetch an op-code from memory. The SYNC (or, for 65816, VPA and VDA) output(s) will be high.
  • save the op-code internally on-chip
  • increment the Program Counter
  • perform whatever specific actions are required by the op-code
When an interrupt is required, the process changes only slightly:
  • wait until the currently-executing instruction is (almost*) complete.
  • use the Program Counter to drive the address bus and thus fetch an op-code from memory. The output(s) will be high, even though the opcode won't execute.
  • discard the op-code that was fetched. Instead, save a BRK op-code ($00) internally on-chip
  • do not increment the Program Counter
  • perform whatever specific actions are required by the op-code (in this case, BRK)
There are slight differences between BRK resulting from an interrupt and BRK resulting from a software BRK instruction fetched from memory. I'm using the term loosely.

The point about not incrementing the Program Counter is simple when you think about it. Since an op-code was fetched but not executed (being pre-empted by BRK), it's necessary that, after the interrupt and its service routine are complete, the opcode be fetched again for another attempt. In order to fetch that same op-code again, the PC (which gets pushed to stack by BRK then restored upon RTI) must be the same -- ie, not incremented.

Re: almost* -- The subtle reality is that many instructions are able to perform their final cycle internally (without using the bus). Exploiting that fact, 65xx CPU's save a cycle by allowing the op-code fetch to occur simultaneously. The internal behavior is hidden, and generally of no relevance -- a curiosity.

It may seem wasteful that an interrupt causes an opcode to be fetched and then discarded. But the internal operation just described necessitates a one-cycle delay anyway, so the wasted fetch is of no consequence.

HTH! Cheers,

Jeff

Re: interupts

Posted: Sat May 11, 2013 5:30 pm
by Gadersd
Thanks! Your answer was very helpful. I am planning on eventually building the hardware from ics.

Re: interupts

Posted: Sat May 11, 2013 6:05 pm
by Gadersd
I just read that the brk instruction loads the PC with the address at FFFF and FFFE. How would this work when the NMI and RESET are located at different addresses?

Re: interupts

Posted: Sat May 11, 2013 6:17 pm
by GARTHWILSON
Gadersd wrote:
I just read that the brk instruction loads the PC with the address at FFFF and FFFE. How would this work when the NMI and RESET are located at different addresses?
BRK uses the same vector as IRQ, but NMI uses a different one.  If there's a possibility that BRK caused the interrupt (ie, it was a software interrupt and not a hardware interrupt), then the interrupt-service routine (ISR) for IRQ needs to test the B flag in the stacked record of the status register to see if BRK indeed is what happened.  Myself, I haven't used BRK since I was in school using AIM-65's in 1982.

Make sure you've read the 6502 interrupts primer.

Re: interupts

Posted: Sun May 12, 2013 8:30 am
by John West
I don't know how the 6502 actually does this, but if I was designing it, I'd have the logic that generates the vector address look at /NMI and /RESET. You could almost just feed those two inputs directly to the appropriate address lines (A2 and A1 respectively), except you have to handle the case where both are asserted at the same time (/RESET has priority). And it'd probably be best to store both inputs at the moment the opcode is fetched, just in case they change later (it would be very bad if one changed half way through fetching the vector).

I never thought of it before, but it's likely that this is why BRK is $00 on the 6502. In NMOS, overriding a signal with a 0 takes just one transistor.

Re: interupts

Posted: Sun May 12, 2013 9:37 am
by Arlet
In my 6502 core, all of RESET/NMI/IRQ are implemented by faking a BRK instruction, and then setting the program counter to the appropriate vector.

Re: interupts

Posted: Sun May 12, 2013 3:11 pm
by GARTHWILSON
Quote:
I never thought of it before, but it's likely that this is why BRK is $00 on the 6502.
As stated in the 6502 interrupts primer, BRK was originally used mainly for patching code in PROMs back when re-assembling and programming was a long, slow process, and each iteration could be quite expensive if the PROM was not erasable.  Unprogrammed bits in the PROM were 1's and programmed bits were 0's.  (This is still true of PROMs, EPROMs, EEPROMs, and flash, but the latter three are erasable.)  If you had a programming mistake, you could program all the bits of an instruction byte to 0 (regardless of their previous values) to cause the BRK, then put the BRK handler in a portion of previously unused memory to go around the erroneous code by doing something else and then jumping back to the original code at a later point.  To fix several places at once, you could make the BRK handler look at the "signature" byte (ie, the byte right after the 00 BRK instruction) to see which one it came from.  If they weren't all different, hopefully you could blow another bit here or there to make them unique.  This is why BRK is a two-byte instruction.

Re: interupts

Posted: Sun May 12, 2013 6:29 pm
by BigDumbDinosaur
GARTHWILSON wrote:
...This is why BRK is a two-byte instruction.

As is COP on the 65C816. The assembly language syntax for COP requires that a signature byte be present, which makes it different from BRK in that respect—also, COP has its own vector.

Now for something interesting: if one studies the instruction execution sequences of BRK and COP, it is seen that during cycle 2 reference is made to the signature byte—VPA is valid at that time, indicating that a fetch from program code is in progress. The signature is in fact loaded by the '816 but doesn't show up in a register. How cool would it be if the signature could have somehow been made to be accessible in the MPU instead of by getting the RTI address off the stack and decrementing it to get to the signature?