Z80 Interrupts

Interrupt Response

An interrupt allows peripheral devices to suspend CPU operation and force the CPU to start a peripheral service routine. This service routine usually involves the exchange of data, status, or control information between the CPU and the peripheral. When the service routine is completed, the CPU returns to the operation from which it was interrupted.

Interrupt Enable/Disable

The Z80 CPU contains two interrupt inputs: a software maskable interrupt and a nonmaskable interrupt. The nonmaskable interrupt cannot be disabled by the programmer and is accepted when a peripheral device requests it. This interrupt is generally reserved for important functions that can be enabled or disabled selectively by the programmer. This routine allows the programmer to disable the interrupt during periods when the program contains timing constraints that wont allow interrupt. In the Z80 CPU, there is an interrupt enable flip-flop (IFF) that is set or reset by the programmer using the Enable Interrupt (EI) and Disable Interrupt (DI) instructions. When the IFF is reset, an interrupt cannot be accepted by the CPU.

The two enable flip-flops are IFF1 and IFF2

The state of IFF1 is used to inhibit interrupts while IFF2 is used as a temporary storage location for IFF1.

A CPU reset forces both the IFF1 and IFF2 to the reset state, which disables interrupts. Interrupts can be enabled at any time by an EI instruction from the programmer. When an EI instruction is executed, any pending interrupt request is not accepted until after the instruction following EI is executed. This single instruction delay is necessary when the next instruction is a return instruction. Interrupts are not allowed until a return is completed. The EI instruction sets both IFF1 and IFF2 to the enable state. When the CPU accepts a maskable interrupt, both IFF1 and IFF2 are automatically reset, inhibiting further interrupts until the programmer issues a new El instruction.

NOTE:For all of the previous cases, IFF1 and IFF2 are always equal

The purpose of IFF2 is to save the status of IFF1 when a nonmaskable interrupt occurs. When a nonmaskable interrupt is accepted, IFF1 resets to prevent further interrupts until reenabled by the programmer. Therefore, after a nonmaskable interrupt is accepted, maskable interrupts are disabled but the previous state of IFF1 is saved so that the complete state of the CPU just prior to the nonmaskable interrupt can be restored at any time. When a Load Register A with Register I (LD A, I) instruction or a Load Register A with Register R (LD A, R) instruction is executed, the state of IFF2 is copied to the parity flag, where it can be tested or stored.

A second method of restoring the status of IFF1 is through the execution of a Return From Nonmaskable Interrupt (RETN) instruction. This instruction indicates that the nonmaskable interrupt service routine is complete and the contents of IFF2 are now copied back into IFF1 so that the status of IFF1 just prior to the acceptance of the nonmaskable interrupt is restored automatically.

Below table is a summary of the effect of different instructions on the two enable flip-flops.

CPU Reset00Maskable interrupt, disabled
DI Instruction Execution00Maskable interrupt disabled
EI Instruction Execution11Maskable interrupt enabled
LD A,I Instruction Execution**IFF2 -> Parity flag
LD A,R Instruction Execution**IFF2 -> Parity flag
Accept Non-maskable Interrupt0*Maskable -> Interrupt
RETN Instruction ExecutionIFF2*IFF2 -> Indicates completion of nonmaskable interrupt service routine

CPU Response

The CPU always accepts a nonmaskable interrupt. When this nonmaskable interrupt is accepted, the CPU ignores the next instruction that it fetches and instead performs a restart at address 0066h. The CPU functions as if it had recycled a restart instruction, but to a location other than one of the eight software restart locations. A restart is merely a call to a specific address in Page 0 of memory.

The CPU can be programmed to respond to the maskable interrupt in any one of three possible modes

Mode 0

Mode 0 is similar to the 8080A interrupt response mode. With Mode 0, the interrupting device can place any instruction on the data bus and the CPU executes it. Consequently, the interrupting device provides the next instruction to be executed. Often this response is a restart instruction because the interrupting device is required to supply only a single-byte instruction. Alternatively, any other instruction such as a 3-byte call to any location in memory could be executed.

The number of clock cycles necessary to execute this instruction is two more than the normal number for the instruction. The addition of two clock cycles occurs because the CPU automatically adds two wait states to an Interrupt response cycle to allow sufficient time to implement an external daisy-chain for priority control. After the application of RESET, the CPU automatically enters interrupt Mode 0.

Mode 1

When Mode 1 is selected by the programmer, the CPU responds to an interrupt by executing a restart at address 0038h. As a result, the response is identical to that of a nonmaskable interrupt except that the call location is 0038h instead of 0066h. The number of cycles required to complete the restart instruction is two more than normal due to the two added wait states.

Mode 2

Mode 2 is the most powerful interrupt response mode. With a single 8-bit byte from the user, an indirect call can be made to any memory location.

In Mode 2, the programmer maintains a table of 16-bit starting addresses for every interrupt service routine. This table can be located anywhere in memory. When an interrupt is accepted, a 16-bit pointer must be formed to obtain the required interrupt service routine starting address from the table. The upper eight bits of this pointer is formed from the contents of the I Register. The I register must be loaded with the applicable value by the programmer, such as LD I, A. A CPU reset clears the I Register so that it is initialized to 0. The lower eight bits of the pointer must be supplied by the interrupting device. Only seven bits are required from the interrupting device, because the least-significant bit must be a 0. This process is required, because the pointer must receive two adjacent bytes to form a complete 16-bit service routine starting address; addresses must always start in even locations.

The first byte in the table is the least-significant (low-order portion of the address). The programmer must complete the table with the correct addresses before any interrupts are accepted.

The programmer can change the table by storing it in read/write memory, which also allows individual peripherals to be serviced by different service routines.

When the interrupting device supplies the lower portion of the pointer, the CPU automatically pushes the program counter onto the stack, obtains the starting address from the table, and performs a jump to this address. This mode of response requires 19 clock periods to complete (seven to fetch the lower eight bits from the interrupting device, six to save the program counter, and six to obtain the jump address).