CPC Guide - Z80 Interrupt handling on the CPCZ80 Interrupt handling on the CPC General Interrupt information This document explains how the interrupts are handled in the CPC. The Z80 has the provision for 2 interrupt types; Maskable interrupts, and Non-Maskable Interrupts (NMI). When the device wants to cause a maskable interrupt a low should be applied to INT pin, for non-maskable interrupts a low to NMI pin. Maskable Interrupts This interrupt type can be enabled or disabled using a Z80 opcode (EI will enable maskable interrupts and DI will disable maskable interrupts). There are 3 modes of maskable interrupt depending on what the user wants. The mode is also specified with a Z80 opcode (IM0, IM1 or IM2). Each mode is slightly different in the way that it performs the interrupt. See this document for more information about how each maskable interrupt works. This interrupt is used in the CPC. The rate of interrupts is fixed, and is controlled by the Gate Array. Non-Maskable Interrupts NMI This type of interrupt cannot be disabled and it has the highest priority. This type is not actually used in the CPC and so it is not supported, but the signal can be found on the expansion port if the user wishes to use it. (The Multiface 2 uses the NMI interrupt to freeze the current program). When the Z80 recieves a NMI interrupt it will do the following: Push current program counter onto the stack Jump to &0066 in memory. In all cases the Z80 will send an acknowledgement when it is ready to continue with the interrupt. (In Interrupt Mode 2, the device can use the acknowledgement to put the interrupt vector onto the z80 bus). So for maskable interrupts, the process is: Apply low to INT pin Z80 will finish the current command, and then depending on the interrupt mode, it may put the return address onto the stack. When the z80 is ready, it will acknowledge the interrupt by M1 and IORQ being low Interrupts in the CPC The following information may not be exactly correct, but this is my current understanding The section above described how the z80 handles interrupts, this section will attempt to describe how interrupts are performed in the CPC. In the CPC, the Gate Array is responsible for generating interrupt requests, and ensuring that interrupts do not occur to close together (especially if interrupts have been disabled and are enabled again just before another interrupt request). The Gate Array contains a 6-bit counter. This is incremented after each HSYNC signal from the CRTC. So in a way it is a scanline counter. The counter is used to determine when interrupts will occur. Basically, when the counter reaches 52, the Gate Array will send the INT request to the Z80, and then wait for the z80 to acknowledge. (If the z80 has interrupts enabled, it will respond immediatly, otherwise there might be sometime before it does). The gate array will continue to count scanlines and increment the counter during this time. So each interrupt effectively splits the screen into 52 scanline tall blocks. And there are (39*8) total lines, so this gives 6 interrupt regions or "interrupt blocks". To ensure the interrupts are at the same place every screen refresh, the gate array will synchronise with the VSYNC signal from the CRTC. It is possible that the current interrupt request is not acknowledged, because the Z80 has disabled interrupts. The gate array will continue to wait until there is acknowledgement. However, since the counter still continues, it is possible that the interrupts are enabled just before a new interrupt request is made. In this case, the interrupts would be very close together and could cause problems (especially if interrupt handling routine takes a while). So, the gate array clears the top bit of the counter. This will effectively ensure that the new interrupt which is about to occur is suspended for a short amount of time so the interrupt handling routine has time to execute. The top bit of the counter can also be cleared by using a bit in one of the gate array registers, so you can control the position of an interrupt if you require. If you had some code which used some time, and it's operation would be spoiled by an interrupt, then you could use this function of the gate array register to suspend the interrupt for a few lines until your program is able to finish. Notes The Gate Array uses the VSYNC to synchronise interrupts, so that they occur at the same time for each screen refresh. It waits for the start of the VSYNC, and now it will be synchronised, it will then wait for another 2 lines (to give time for software to recognise the VSYNC) before the first interrupt is requested. The Gate Array will clear the scanline counter at this time. When the Gate Array sends a INT request to the z80 it will wait for it to be acknowledged. (This may be almost immediate if interrupts are enabled, or a long time if interrupts are disabled). During this time, the INT pin of the z80 is low, and the Gate Array will continue to count lines. If interrupts are acknowledged, the gate array will clear the interrupt by putting INT high. If interrupts are disabled, it will wait until interrupts are enabled (as soon as they are enabled, the z80 will notice the int request and acknowledge it). If interrupts are enabled, the z80 will start to prepare for the interrupt and then send acknowledgement to the gate array which will clear the interrupt. The Gate Array has an "interrupt disable bit". In reality, this performs two functions. It will clear any pending interrupt, and it will also clear the top bit of the counter (this has the effect of making sure that two interrupts do not occur close together). When interrupts are enabled If interrupts are enabled and a interrupt request is sent, and the counter>52 when the acknowledge comes back, then the top bit of the scanline counter is cleared. (This is done to ensure the next interrupt is not to close to the one being executed). A interrupt will be sent from the Gate Array when the scanline counter is to equal to 52 and the counter will then be cleared. Quote from the firmware manual, Appendix 12.1: "The processor interrupt pin is driven by a flip-flop in the VGA. This FF is set during every vertical flyback and every 52 scan lines thereafter until the next VF. The interrupt is arranged to occur approx. 2 scans (125 us) into the 8 scan (500 us) VF signal. The interrupt latch is cleared by the processor acknowledging the interrupt, or explicitly, using a software command. The top bit of the divide by 52 counter is also cleared when the processor acknowledges an interrupt occurring after this counter has overflowed. This allows the interrupt system to be expanded."