Interrupt timing and writes to acknowledge them

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Interrupt timing and writes to acknowledge them
by on (#95296)
Let's say that you are doing a write to clear an interrupt at almost the same time as the interrupt happens.
The CPU cycle that writes to memory happens at W.
The IRQ flag from the interrupting device happens at I.
Code:
....I
...W

In this case, the interrupt happens after the write to acknowledge it, so you clearly get an interrupt.

Code:
..I
...W

In this case, the interrupt happens before the CPU instruction writes to clear it, and the CPU clears it, so no interrupt happens.

Code:
...I
...W

But what about the condition where there's a tie?

by on (#95298)
I believe it's called "race condition". If you consider the IRQ is acknowledged in the last cycle of the current instruction and reading/writting from/to a register occurs before the acknowledge, I'd say the IRQ occurs.

One example is the VBlank flag. From the test roms: "flag should read as set 0 PPU clocks after VBL". It means reading $2002 right on VBlank cycle, which should clear it.

I may be wrong, though...

by on (#95305)
The CPU instruction gets precidence in the case of a tie. Existing 65xxx docs (I can point you to the exact document/page/paragraph if you want to read it) state that in the case of an interrupt occurring in the middle of a CPU instruction, the CPU instruction finishes normally then the interrupt happens.

There's only one gotcha to this, and it's one I'm curious about myself:

Let's say the instruction in question is SEI and the incoming interrupt is a hardware IRQ (not NMI; NMI always happens independent of the i bit in P). Let's say the hardware IRQ happens after the 1st but before the 2nd cycle of SEI. In this case, I'm not sure what happens; would the CPU would finish doing the 2nd cycle of SEI, thus bit i would be set, then the interrupt would be ignored because i is set? I simply don't know. I'm sure someone could verify the actual behaviour using visual6502.org (that's exactly why it exists, to determine situations/cases like this!)

by on (#95308)
I was always under the impression that as part of the pipelining process, the CPU looks for interrupts one cycle before the end of the instruction.

So in the case you described, koitsu, the status of the I flag and any pending IRQ would be relevant only at the end of the first cycle of SEI. If the interrupt happens after that, the CPU has already begun pipelining the next instruction and it would be too late to interrupt.

But that's complete speculation on my part.

by on (#95310)
The thing is it doesn't depend as much as what's happening with the CPU as what's happening with the device that generating the IRQ.

koitsu: while what you're saying about the CPU finishing the instruction before handling the IRQ is true, your answer assumes the IRQ is actually generated. The question here is also dependent on whether it was ever generated in the first place.

For example if you considered and IRQ from something like the MMC3 scanline counter. Now extremely specific details on the MMC3 like this aren't really known. But one thing is pretty apparent, rising edges of CHR A12 trigger IRQs assuming they are enabled. So since CHR A12 is on a faster clock than the CPU there are 3 times that the IRQ could be triggered for a given CPU cycle etc.

But the real question is were IRQs enabled when the IRQ triggering event occured. If yes, you get an IRQ if not you don't. But then the second (6502) question is how long does the IRQ line have to be asserted in order for the CPU to recognize it?

You could assume that writes (disabling IRQs) happen on the second half of the CPU cycle. So CHR A12 rises late or early in the cycle you might get different responses. Early in the cycle and I'd imagine the MMC3 would generate and IRQ breifly before getting disabled. However being an open collector signal the line probably doesn't have enough time to get pulled low enough for the CPU to see it. I could go on and on about what might happen if it comes late in the CPU cycle.

But really the best answer here is it's unpredictable/unknown behavior. Knowing more details about how the MMC3 disables IRQs exactly you might be able to answer your question but that only answers if for the MMC3.

Your second question about SEI is a completely different question really. I'd imagine that your right that you could answer that question with the visual6502. Although it may very well still depend on when during the CPU cycle the device generates the IRQ, the visual6502 will probably let you know whether it does or not.

by on (#95336)
infiniteneslives wrote:
But the real question is were IRQs enabled when the IRQ triggering event occured. If yes, you get an IRQ if not you don't. But then the second (6502) question is how long does the IRQ line have to be asserted in order for the CPU to recognize it?

I had some discussion on this previously with the 6502.org folks. I also ran some Visual6502 simulations...

This shows an acknowledged IRQ that is a half-CPU-cycle long.

This shows an unacknowledged IRQ that is a half-CPU-cycle long.

by on (#95347)
cpow wrote:
I had some discussion on this previously with the 6502.org folks. I also ran some Visual6502 simulations...


Well I guess that further proves my point that it's unpredictable...

Out of curiosity what is the difference between the two?

One other thing not simulated there is the pull-up on the IRQ line. So depending on the strength of the device firing the IRQ a half cycle long IRQ has even less of a chance of getting acknowledged.

by on (#95353)
infiniteneslives wrote:
cpow wrote:
I had some discussion on this previously with the 6502.org folks. I also ran some Visual6502 simulations...


Well I guess that further proves my point that it's unpredictable...

Out of curiosity what is the difference between the two?

One other thing not simulated there is the pull-up on the IRQ line. So depending on the strength of the device firing the IRQ a half cycle long IRQ has even less of a chance of getting acknowledged.


The difference between the two is just what half-cycle the IRQ 'fires' on. You can see it in the trace at bottom-right under the irq column.

As was pointed out in the 6502.org forum where this discussion took place, the typical usage of IRQ is to pull it active until some action causes the thing pulling it active to let it go. Thus, a half-CPU-cycle IRQ isn't a typical occurrence. But it's relevant here because it shows [I think] where the sensing of the interrupt occurs [the Break flag clearing in the second half-cycle.

I would carry this over to visual2a03 but it doesn't seem to accept the toggling of the IRQ input.

by on (#95461)
If your test/affirmation is correct, regarding the interrupt IRQ triggering, so I have to disagree about blargg's VBlank flag test on $2002 reads, which would sound absurd.

by on (#95466)
cpow wrote:
I would carry this over to visual2a03 but it doesn't seem to accept the toggling of the IRQ input.

Quietust has addressed the problem I mentioned above so now IRQs can be fed to Visual2A03. While looking at that I got sidetracked by the sprite DMA versus DMC DMA conversation that I'd wanted to run through Visual2A03. This thread was the result of that. Hopefully I have more time to play with Visual2A03.