Interrupts - redcode/Z80 GitHub Wiki
Apart from the special reset, which can be considered a pseudo interrupt, the Z80 provides two types of interrupts.
Maskable interrupt (INT)
The maskable interrupt can be enabled and disabled by using the ei
and di
instructions respectively, which control the state of the interrupt enable flip-flops (IFF1 and IFF2). The CPU does not accept this kind of interrupt directly after an ei
instruction, but only after the one following ei
is executed. This is so that ISRs can return without the danger of being interrupted immediately after re-enabling interrupts if the $\overline{\texttt{INT}}$ line is still active, which could cause a stack overflow.
As in ei
, all forms of reti
and retn
defer the acceptance of the maskable interrupt for one instruction, but this only occurs when IFF1 and IFF2 do not have the same state prior to the execution of either of these instructions, which can only be caused by an earlier NMI response.
This interrupt has three operation modes, which are selected through the im
instruction:
Mode 0
An instruction supplied via the data bus is executed. Its first byte is read during the INT acknowledge cycle (INTA). If it is an opcode prefix, additional M-cycles of this kind are produced until the final opcode of the instruction is fetched. Each INT acknowledge cycle consumes as many T-states as its normal M1 counterpart (the opcode fech M-cycle) plus the 2 wait T-states mentioned above. Subsequent bytes of the instruction are fetched by using normal memory read M-cycles, during which the interrupting I/O device must still supply the data. The PC register, however, remains at its pre-interrupt state, not being incremented as a result of the instruction fetch.
Mode 1
An internal rst 38h
is executed. The interrupt response data read from the data bus during the INT acknowledge cycle is ignored.
Mode 2
An indirect call is executed. The pointer to the ISR is loaded from the memory address formed by taking the I register as the most significant byte, and the interrupt response vector read from the data bus as the least significant byte.
Note: Zilog's official documentation states that the least significant bit of the interrupt response vector "must be a zero", since the address formed "is used to get two adjacent bytes to form a complete 16-bit service routine starting address and the addresses must always start in even locations". However, Sean Young's experiments confirmed that there is no such limitation; any vector works whether it is odd or even.
Non-maskable interrupt (NMI)
The non-maskable interrupt takes priority over the maskable interrupt and cannot be disabled under software control. Its usual function is to provide immediate response to important signals. The CPU responds to an NMI by pushing PC onto the stack and jumping to the ISR located at address 0066h
(which is equivalent to an internal rst 66h
). The interrupt enable flip-flop 1 (IFF1) is reset to prevent any INT from being accepted during the execution of this routine, which is usually exited by using a reti
or retn
instruction to restore the original state of IFF1.
The CPU does not accept a second NMI during the NMI response. Therefore, it is not possible to chain two NMI responses in a row without executing at least one instruction between them.
Note: Some technical documents from Zilog include an erroneous timing diagram showing an NMI acknowledge cycle of 4 T-states. However, documents from other manufacturers and third parties specify that this M-cycle has 5 T-states, as has been confirmed by low-level tests and electronic simulations.