8

A page on how to do raster interrupts includes the following code

Irq:     LDA #7
         STA $D020   ; Turn screen frame yellow
         LDX #90
Pause:   DEX
         BNE Pause   ; Empty loop that "does nothing" for a little under a half millisecond
         LDA #0
         STA $D020   ; Switch frame color back to black
         ASL $D019   ; "Acknowledge" the interrupt by clearing the VIC's interrupt flag.
         JMP $EA31   ; Jump into KERNAL's standard interrupt service routine to handle keyboard scan, cursor display etc.

I'm interested in the second-to-last line. Why "acknowledge" it? I just want to understand what that does. My understanding is that the VIC-II sets some flag, and this line of code clears that flag, to show that the interrupt has been handled.

  • But if we know we have just serviced an interrupt, then we also know that the interrupt has been serviced. That's trivial.
  • Also, I don't believe the Commodore KERNAL ever looks at the VIC-II. So I think we can rule out an operating system requirement.
  • Also, the VIC-II will fire the same interrupt a frame later, because interrupt enable is not in register $d019, it's in $d01a. So we can rule out a requirement coming from the hardware.
0

3 Answers 3

15

The VIC keeps the CPU interrupt line activated until the cause for the interrupt is acknowledged, so if you don't tell the VIC which of the interrupts are now handled it won't release the CPU interrupt line and CPU keeps executing the interrupt routine.

13

The 6502 is designed to be used in systems with devices that may need to cause an interrupt. The way this is accommodated is by having each device use an open-collector/open-drain output to drive the /IRQ pin, which is passively pulled up with a resistor. If any device wants the /IRQ pin low, it will be low. Only if no device wants it low will it be high.

When an IRQ occurs, the handler will initially have no idea which device requested it. The usual practice is for each device to provide a means of asking whether it requested an interrupt, and for the device to keep on requesting an interrupt until the CPU does whatever the device needed it to do. Suppose there are two devices and the second one needs service. It will drive IRQ, whereupon the interrupt service routine will check whether the first device needs service (it won't), so the interrupt service routine will check the second device, see that it needs service, and start servicing it.

If the first device decided it needed service at some point while the second device was being serviced, the first device would start driving IRQ (which the second device may or may not still be driving). After code finishes servicing the second device, it will execute an RTI which will re-enable interrupts. As soon as that happens, the asserted /IRQ line will cause the CPU to re-invoke the interrupt handler, which will then ask whether the first device needs service (it will), and thus service the first device.

For some kinds of devices such as UARTs ("serial ports") and interrupts (e.g. "incoming character received") it may not be necessary to explicitly acknowledge interrupts. If an interrupt indicates that a character has been received but code hasn't yet read it, the act of reading all characters that have been received would clear the condition until more characters arrive. For something like the raster interrupt on the VIC-II, however, the only way the VIC-II can know that the processor has noticed that it has requested an interrupt is for the processor to indicate that by writing to $D019. Using ASL is a handy way of writing a suitable value.

8

The 6502 only has a single IRQ line which is used by any device connected to it. In the C64, we have the CIA#1 and the VIC-II connected to IRQ.

The CPU reacts on a signalled IRQ only if its interrupt flag is cleared. When starting to service an IRQ, the interrupt flag is set automatically and will stay set until either the end of the ISR (Interrupt service routine) on rti or the routine explicitly clears it with cli*). So, if the CPU is in the middle of servicing an IRQ, it normally won't start servicing another one. Therefore, any device will keep signalling an IRQ until it is told to stop by acknowledging it, it's the only way for the device to "know" the IRQ is being serviced. If the VIC-II wants an interrupt while a CIA#1-IRQ is being serviced -- it has to wait. Note this is normally bad because VIC-II IRQs are often timing critical, so in a real-world C64 program, you will make sure that only the VIC-II will generate IRQs. You still have to acknowledge them because the VIC-II can't know about this.

If you fail to acknowledge an IRQ before the interrupt flag is cleared, the CPU will instantly start to service it again, effectively locking up in an "endless IRQ loop".

As a side note: the NMI line works differently. NMIs don't care about the interrupt flag (so they will always be serviced when they occur), and they are edge-triggered, which means the CPU only reacts on a change of the signal. Therefore, it's possible to "block" NMIs by deliberately not acknowledging one -- NMI will stay signalled and no other NMI will ever change that signal again unless the previous one is acknowledged.

Disclaimer: The existing answers are absolutely correct, but it's an interesting question, so I thought another approach explaining it won't hurt :)


*) this allows you to have "nested" ISRs, which is sometimes a nice thing. It can for example be used to implement some simple "job priority": Your main logic runs in normal code, you have one ISR per frame that does something expensive (like scrolling the screen) and immediately acknowledges the IRQ and clears the interrupt flag to allow some short ISRs to be triggered, e.g. for some rasterbars.

2
  • You sure that CIA#1 is connected to IRQ? I think it's connected to NMI, which CIA#2 is connected to IRQ. I could be wrong. Commented Jan 22, 2019 at 10:13
  • See e.g. sta.c64.org/cbm64mem.html -- CIA#1; inputs (keyboard, joystick, mouse), datasette, IRQ control -- CIA#2; serial bus, RS232, NMI control :) Commented Jan 22, 2019 at 10:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .