According to multiple documentation sources, non-maskable interrupts (NMIs) can be nested (or reentrant) in a Z80 microprocessor.
This is, upon a /NMI
signal pulse, the CPU will interrupt the current program by resetting IFF1
to disable maskable interrupts, pushing the program counter in the stack and jumping to address 0x0066 to execute the interrupt service routine there.
The point is that a new /NMI
signal pulse can interrupt the ongoing ISR before it ends with a RETN
instruction. This is documented in The Undocumented Z80 Documented and confirmed in other StackExchange questions. When this happens, there is an odd case that, if permitted, would derive in an abnormal situation.
If maskable interrupts were enabled before the NMI was accepted, the first invocation of the ISR will execute with IFF1
reset and IFF2
set. This is the well-known mechanism to restore IFF1
from IFF2
by RETN
instruction when ISR terminates, so the user-defined interruption config is honored.
When the second /NMI
pulse is detected before RETN
takes place, a new NMI is accepted by the CPU. It will perform exactly the same procedure as the outer ISR: reset IFF1
, push PC
in the stack and jump to 0x0066.
Now let's say the inner ISR ends with a RETN
instruction without any further NMI reentrance. This will copy IFF2
into IFF1
, pop the PC
from the stack, and continue with the execution of the ISR of the outer NMI. As maskable interrupts were enabled since the very beginning, this will effectively enable those interrupts. And the ISR of the outer NMI will execute such that it can be interrupted again by a maskable interrupt.
In other words, nested or reentrant NMIs can derive in situations where maskable interrupts are enabled, and a /INT
signal can interrupt the execution of a NMI. This is equivalent to putting a EI
instruction in the code of the NMI service routine.
After this, I am not sure if there is something I am not considering, or just that this is a flaw of the original design of the CPU. I checked the source code of a few Z80 emulators (MAME included), and all them operate as I am assuming. If that's how the things work, is /NMI
something that have to be used very carefully? Do designers have to consider this and ensure /NMI
cannot have multiple pulses? Or perhaps it is totally OK to have maskable interrupts interrupting NMIs? Am I exaggerating the situation then?