Hello,
It's been a while since I posted something in the forum. I started developing a NES emulator in C/C++ many years ago (maybe 17), and I'm working on it every now and then when I have free time for it. Currently it supports most simple mappers an all but the most complicated MMCs and VRCs. Recently, full audio support was added and outputted (and actually, now the emulator is more-or-less synchronized to the audio output callback function). It uses SDL, for now.
A band-limited approach was implemented for the audio.
The emulator has many timing issues though, and thy are caused by the not-perfect architecture of the CPU-PPU-APU-MAPPER relationship, which needs to be reworked in order to achieve good and efficient per-cycle emulation. Most supported games are playable with some minor hacks and assumptions in the emu code though, sometimes with minor glitches.
The above was just for introduction, now to the main question. Excuse me, if there is a topic describing this in detail, I would like to read it if you post a link.
The question is:
We know that 6502 has NMI and IRQ. As far as I know, NMI is edge-triggered, while IRQ line is level-triggered, and as long as the CPU's Interrupt Inhibit flag is clear, IRQs will be fired all the time if the IRQ line is kept low.
There are different sources of IRQ, like the DMC channel, Frame Counter or mapper. For this reason, in my CPU emulation, i have a irqLine variable, which has a separate bit for every different source of IRQ, and even if only one of these bits is set, I assume the CPU IRQ line is low (so that each source of IRQ can clear its own bit, without affecting the other pending IRQs from other sources). In practice, this approach often makes the emulation get stuck in an endless IRQ loop. So often times (in MMC3, VRC4, DMC, FC) i just call the IRQ routine without actually setting anything in the irqLine variable.
This raises many questions for me:
- When do different sources "release" the IRQ line. When the corresponding source's IRQ is acknowledged through the appropriate memory-mapped port? Or the IRQs go down on their own after some time (MMCx, VRCx, FC, DMC...).
- What should be the CPU behavior when some source is still keeping the IRQ line low for a long time (in the ISR, routine, which I have no control of, and on executing RTI...)? As far as I know, in this case the CPU can only avoid jumping to the IRQ vector all the time only if it has the InterruptInhibit flag set, and it is affected by instructions like CLI / SEI / RTI.
I'm a little confused about the IRQs and I don't know if I'm omitting something in the emulation.
Thank you in advance!
It's been a while since I posted something in the forum. I started developing a NES emulator in C/C++ many years ago (maybe 17), and I'm working on it every now and then when I have free time for it. Currently it supports most simple mappers an all but the most complicated MMCs and VRCs. Recently, full audio support was added and outputted (and actually, now the emulator is more-or-less synchronized to the audio output callback function). It uses SDL, for now.
A band-limited approach was implemented for the audio.
The emulator has many timing issues though, and thy are caused by the not-perfect architecture of the CPU-PPU-APU-MAPPER relationship, which needs to be reworked in order to achieve good and efficient per-cycle emulation. Most supported games are playable with some minor hacks and assumptions in the emu code though, sometimes with minor glitches.
The above was just for introduction, now to the main question. Excuse me, if there is a topic describing this in detail, I would like to read it if you post a link.
The question is:
We know that 6502 has NMI and IRQ. As far as I know, NMI is edge-triggered, while IRQ line is level-triggered, and as long as the CPU's Interrupt Inhibit flag is clear, IRQs will be fired all the time if the IRQ line is kept low.
There are different sources of IRQ, like the DMC channel, Frame Counter or mapper. For this reason, in my CPU emulation, i have a irqLine variable, which has a separate bit for every different source of IRQ, and even if only one of these bits is set, I assume the CPU IRQ line is low (so that each source of IRQ can clear its own bit, without affecting the other pending IRQs from other sources). In practice, this approach often makes the emulation get stuck in an endless IRQ loop. So often times (in MMC3, VRC4, DMC, FC) i just call the IRQ routine without actually setting anything in the irqLine variable.
This raises many questions for me:
- When do different sources "release" the IRQ line. When the corresponding source's IRQ is acknowledged through the appropriate memory-mapped port? Or the IRQs go down on their own after some time (MMCx, VRCx, FC, DMC...).
- What should be the CPU behavior when some source is still keeping the IRQ line low for a long time (in the ISR, routine, which I have no control of, and on executing RTI...)? As far as I know, in this case the CPU can only avoid jumping to the IRQ vector all the time only if it has the InterruptInhibit flag set, and it is affected by instructions like CLI / SEI / RTI.
I'm a little confused about the IRQs and I don't know if I'm omitting something in the emulation.
Thank you in advance!
Statistics: Posted by EvtimDjerekarov — Mon Nov 04, 2024 3:46 am — Replies 3 — Views 183