6502 interrupts page

Let's talk about anything related to the 6502 microprocessor.
ulfalizer
Posts: 44
Joined: 31 May 2013

6502 interrupts page

Post by ulfalizer »

In case anyone's interested, I've put together a page with detailed (or at least more detailed and less vague than I could find elsewhere) information on 6502 interrupt behavior and timing at http://wiki.nesdev.com/w/index.php/CPU_interrupts . It checks out in Visual 6502 and makes blargg's cpu_interrupts_v2 tests pass in my NES emulator, so hopefully it should be correct. Might be handy info for emulator authors. :)
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: 6502 interrupts page

Post by BigEd »

Thanks ulfalizer - I've linked back to you from the visual6502 wiki.
ulfalizer
Posts: 44
Joined: 31 May 2013

Re: 6502 interrupts page

Post by ulfalizer »

You're welcome. :)
RichTW
Posts: 95
Joined: 06 Oct 2010
Location: Palma, Spain

Re: 6502 interrupts page

Post by RichTW »

IRQ is usually polled during the second-to-last cycle of an instruction (two cycles before the opcode fetch).
This surprises me, as I was sure I once set up some simulations in Visual 6502 which showed that the second half of T0 was where IRQs were polled to determine whether to start the interrupt sequence. But sure enough, this simulation demonstrates that /IRQ pulled low for half a cycle during the second half of T3 during a LDA abs is enough to trigger the interrupt immediately afterwards.

This is surely more complicated logic-wise as it means that the determining when to poll IRQs depends on the instruction being executed, instead of being common to the T0 state as I'd previously imagined. Is this the case?
Last edited by RichTW on Wed Aug 28, 2013 12:54 pm, edited 1 time in total.
ulfalizer
Posts: 44
Joined: 31 May 2013

Re: 6502 interrupts page

Post by ulfalizer »

RichTW wrote:
IRQ is usually polled during the second-to-last cycle of an instruction (two cycles before the opcode fetch).
This surprises me, as I was sure I once set up some simulations in Visual 6502 which showed that the second half of T0 was where IRQs were polled to determine whether to start the interrupt sequence. But sure enough, this simulation demonstrates that /IRQ pulled low for half a cycle during the second half of T3 during a LDA abs is enough to trigger the interrupt immediately afterwards.

This is surely more complicated logic-wise as it means that the determining when to poll IRQs depends on the instruction being executed, instead of being common to the T0 state as I'd previously imagined. Is this the case?

Interrupts still seem to get polled during T0 internally (except for branches where they're also polled during T2); it's just that there's a delay from when IRQ is asserted to when the internal signal IRQP goes high. Perhaps it's to stabilize the signal.

For NMIs the signal ~NMIG seems to serve a similar purpose.

Node 646 (which might just be "in T0") along with nnT2BR (presumably "T2 of a branch instruction") seem to define the "polling points" for the internal interrupt signals.
RichTW
Posts: 95
Joined: 06 Oct 2010
Location: Palma, Spain

Re: 6502 interrupts page

Post by RichTW »

OK, here's what I was thinking of - in this post, I posted a simulation URL and noted that "as long as nIRQ is low during the first half of T0, the interrupt sequence will begin, and this is the only place the CPU checks whether an interrupt should be taken or not". Going to this URL now shows /IRQ being pulled low during the second half of T3, so has something changed in Visual6502 recently regarding how the data is tabulated, or how the states are annotated? It looks like something has slipped half a cycle backwards. I'm confused.
ulfalizer
Posts: 44
Joined: 31 May 2013

Re: 6502 interrupts page

Post by ulfalizer »

RichTW wrote:
OK, here's what I was thinking of - in this post, I posted a simulation URL and noted that "as long as nIRQ is low during the first half of T0, the interrupt sequence will begin, and this is the only place the CPU checks whether an interrupt should be taken or not". Going to this URL now shows /IRQ being pulled low during the second half of T3, so has something changed in Visual6502 recently regarding how the data is tabulated, or how the states are annotated? It looks like something has slipped half a cycle backwards. I'm confused.
There was a change recently to make the display less confusing w.r.t. interrupts (and maybe other external signals?): viewtopic.php?f=1&t=2532&start=15#p26701
RichTW
Posts: 95
Joined: 06 Oct 2010
Location: Palma, Spain

Re: 6502 interrupts page

Post by RichTW »

Ah, thank you, I hadn't spotted that.

While we're here, perhaps you could clarify something which still leaves me rather puzzled, looking at the Visual 6502 output (this is going a little off-topic). It is usually stated that T0 represents the opcode fetch state, but looking at Visual 6502, this appears to be happening during T1 (at least the address and data bus values seem to indicate this). So what is really happening in T0? I thought I understood all of this at a basic level a while back, but now I'm reasonably confused again. (I'm interested from the perspective of accurate software simulation; I'm not so hardware-savvy unfortunately, although I'd love to understand the hardware level details better).
ulfalizer
Posts: 44
Joined: 31 May 2013

Re: 6502 interrupts page

Post by ulfalizer »

Another way to phrase the explanation would be to say that there's a level detector on the IRQ input and an edge detector on the NMI input, both reacting to a change during φ2 and asserting their outputs during the following φ1. It's those outputs that are then sampled.

More analog-inclined people could probably give some terminology here.
ulfalizer
Posts: 44
Joined: 31 May 2013

Re: 6502 interrupts page

Post by ulfalizer »

RichTW wrote:
Ah, thank you, I hadn't spotted that.

While we're here, perhaps you could clarify something which still leaves me rather puzzled, looking at the Visual 6502 output (this is going a little off-topic). It is usually stated that T0 represents the opcode fetch state, but looking at Visual 6502, this appears to be happening during T1 (at least the address and data bus values seem to indicate this). So what is really happening in T0? I thought I understood all of this at a basic level a while back, but now I'm reasonably confused again. (I'm interested from the perspective of accurate software simulation; I'm not so hardware-savvy unfortunately, although I'd love to understand the hardware level details better).
No idea to be honest. You're right that T0 seems to be the final cycle rather than the fetch cycle. Perhaps the instruction sequencer is set up in some way that it makes sense to think of it as the initial state, but I'm just guessing...
RichTW
Posts: 95
Joined: 06 Oct 2010
Location: Palma, Spain

Re: 6502 interrupts page

Post by RichTW »

ulfalizer wrote:
Another way to phrase the explanation would be to say that there's a level detector on the IRQ input and an edge detector on the NMI input, both reacting to a change during φ2 and asserting their outputs during the following φ1. It's those outputs that are then sampled.
Yes, that makes sense, thank you. So in this sense it's the IRQP signal which is sampled to determine whether to start the interrupt sequence during T0.
ulfalizer wrote:
No idea to be honest. You're right that T0 seems to be the final cycle rather than the fetch cycle. Perhaps the instruction sequencer is set up in some way that it makes sense to think of it as the initial state, but I'm just guessing...
Perhaps BigEd can shed some light on this. My best guess is that the opcode fetch is still happening during T0 (presumably during φ2), but the results are only 'visible' by the start of T1, or something like that?
ulfalizer
Posts: 44
Joined: 31 May 2013

Re: 6502 interrupts page

Post by ulfalizer »

RichTW wrote:
Perhaps BigEd can shed some light on this. My best guess is that the opcode fetch is still happening during T0 (presumably during φ2), but the results are only 'visible' by the start of T1, or something like that?
Some instructions read/write results during the final T0 cycle though, which speaks against that. See e.g. the LSR zero-page instruction here, where the shifted result is written during the T0 cycle: http://visual6502.org/JSSim/expert.html ... 0&steps=15

All reads/writes output the address during φ1+φ2 and perform the transfer during φ2 btw, and every cycle is either a read or a write cycle.
RichTW
Posts: 95
Joined: 06 Oct 2010
Location: Palma, Spain

Re: 6502 interrupts page

Post by RichTW »

Oh I hadn't spotted that before... so it's as if T1 is the opcode fetch, and T2 the first operand fetch for each instruction, hence the two cycle instructions having a T0+T2 state, in which the operand can be fetched at the same time as the T0 behaviour takes place (polling IRQ, plus any overlapping operations from the previous instruction). I haven't seen this stated anywhere though, not even in the very detailed page on the Visual 6502 wiki.

Thanks for the extra details on when the transfer to/from memory is done, helps the Visual 6502 output make a bit more sense!
RichTW
Posts: 95
Joined: 06 Oct 2010
Location: Palma, Spain

Re: 6502 interrupts page

Post by RichTW »

ulfalizer wrote:
All reads/writes output the address during φ1+φ2 and perform the transfer during φ2 btw, and every cycle is either a read or a write cycle.
Another doubt though - if this is the case, then during a read cycle, why does the data bus already have the fetched value during φ1?
ulfalizer
Posts: 44
Joined: 31 May 2013

Re: 6502 interrupts page

Post by ulfalizer »

Someone correct me if I'm wrong, but I think the two-step pipeline (if it can be called that) in the 6502 works as follows:
  • All instructions need at least three cycles to execute (fetch + decode + carry out).
  • During the decode cycle the data bus is free, and the byte after the opcode is fetched (assuming PC has been incremented) in case it can be made useful.
  • If the final cycle of an instruction does not need to use the data bus (e.g. because it transfers a value between internal registers or changes a flag), it can be overlapped with the opcode fetch for the next instruction, making some instructions effectively one cycle shorter.
As an example, the pointless sequence LDA #0; LDA #1 would then be executed as
  1. Fetch LDA imm opcode
  2. Decode LDA imm opcode and fetch operand
  3. Transfer operand to A and fetch LDA imm opcode
  4. Decode LDA imm opcode and fetch operand
  5. Transfer operand to A and fetch next opcode
    ...
That still doesn't explain why the final cycle is called T0 though.
Post Reply