Raster interrupt
From C64-Wiki
Raster interrupt is an interrupt trigger signal that the VIC-II can supply, if desired, to the CPU whenever the raster in the VIC's video signal reaches a specific line. With a bit of (machine code) programming, this mechanism can be exploited to perform many kinds of VIC "trickery", like having both text and high-res graphics on screen simultaneously, and displaying more than the eight hardware-supported sprites at once.
Setting up a raster interrupt
By default, the system is set up to recieve timer-based signals from CIA-1's Timer A, but instead the VIC needs to be configured to deliver raster interrupt signals. This is handled by a small initialization routine:
Init | LDA #%01111111 | "Switch off" interrupts signals from CIA-1 |
AND $D011 | Clear most significant bit in VIC's raster register | |
LDA #210 | Set the raster line number where interrupt should occur | |
LDA #<Irq | Set the interrupt vector to point to interrupt service routine below | |
LDA #%00000001 | Enable raster interrupt signals from VIC | |
RTS | Initialization done; return to BASIC |
Notice that enabling the raster interrupts from the VIC takes place after setting up everything else. If the interrupts are enabled before e.g. the interrupt vector is re-directed to the new routine, an interrupt may occur just as this vector is being altered, sending the CPU to a "random" address and probably crashing the system.
Using a single interrupt service routine
Here is a very simple interrupt service routine that that "wiggles" the screen frame color (53280) to indicate where on the screen the interrupt occurs:
Irq | LDA #7 | Turn screen frame yellow |
| LDX #90 | Empty loop that "does nothing" for a little under a half millisecond |
LDA #0 | Switch frame color back to black | |
ASL $D019 | "Acknoledge" 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. |
When this is run, the frame, or "border", around the screen is mostly black, except for a yellow stripe at the left and right edges: This stripe appears at raster line #210 as set in the initialization routine, because just as the raster starts out on this pixel line across the screen, the interrupt service routine sets the frame color to yellow. During the pause loop, the raster swipes swipe through 8 whole pixel lines, leaving a 8-pixel-wide stripe before the color is set back to black.
Using multiple interrupt service routines
Raster interrupts are often used with a system of two or more interrupt service routines, handling interrupts triggered at different raster lines: Each routine perfoms it's "own" tasks, then sets up an interrupt to occur at the "next" desired raster line and re-directs the vector at 788–789/$0314–$0315 to point to the next routine associated with that line.
The following example shows two such "concatenated" raster interrupt service routines, splitting the screen in a high-resolution part and a text part: They can be initialized using the routine outlined at the beginning of this article.
The first routine is triggered at raster line 210, and handles the switch from high-res to text mode. It also sets up the interrupt pointer to the second interrupt service routine, and configures the corresponding raster line:
Irq | LDA $D011 | Select text screen mode |
LDA #<Irq2 | Re-direct next interrupt to Irq2 service routine | |
LDA #0 | Next interrupt to occur at raster line no. 0 | |
ASL $D019 | "Acknoledge" the interrupt by clearing the VIC's interrupt flag. | |
JMP $EA31 | Jump to the beginning KERNAL's standard interrupt service routine. |
The second routine handles the switch from text to high-res at raster line 250. It also re-adjusts the interrupt pointer back to the first interrupt service routine, and sets up the raster to trigger it next time the raster passes by line 210:
Irq2 | LDA $D011 | Select text screen mode |
LDA #<Irq | Re-direct next interrupt back to Irq | |
LDA #210 | Next interrupt to occur at raster line no. 210 | |
ASL $D019 | "Acknoledge" the interrupt by clearing the VIC's interrupt flag. | |
JMP $EA81 | Jump to the final part of KERNAL's standard interrupt service routine. |
In this example the "default" interrupt service routine at 59953/$EA31 is "included" through the JMP command at the end of the first of the two raster routines, enabling you to move the cursor, type commands etc. after the interrupt system has started. Notice that only one in such a set of raster-driven interrupt service routine need to end in a jump into the entire KERNAL service routine: The latter routine takes a jump to 60033/$EA81, where the ROM routine pulls back registers etc. from the stack before handing the CPU back to what it was doing when the interrupt occurred.