Raster interrupt

From C64-Wiki
Jump to navigationJump to search
AFL 1970 intro (19.01.1989): In the middle of the screen a white and blue raster bar is shown.

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. This method is often used on the C64/C128 for computer games and demos.

Other 8-bit computers such as the Atari 800, MSX and Amstrad CPC can also use raster (line) interrupts. The 80 Character mode on the C128/VDC cannot use this method.


Setting up a raster interrupt[edit | edit source]

By default, the system is set up to receive 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       SEI                  ; set interrupt bit, make the CPU ignore interrupt requests
           LDA #%01111111       ; switch off interrupt signals from CIA-1
           STA $DC0D

           AND $D011            ; clear most significant bit of VIC's raster register
           STA $D011

           STA $DC0D            ; acknowledge pending interrupts from CIA-1
           STA $DD0D            ; acknowledge pending interrupts from CIA-2

           LDA #210             ; set rasterline where interrupt shall occur
           STA $D012

           LDA #<Irq            ; set interrupt vectors, pointing to interrupt service routine below
           STA $0314
           LDA #>Irq
           STA $0315

           LDA #%00000001       ; enable raster interrupt signals from VIC
           STA $D01A

           CLI                  ; clear interrupt flag, allowing the CPU to respond to interrupt requests
           RTS

Notice that enabling the raster interrupts from the VIC takes place after setting up everything else. Also, the routine starts with SEI, to disable IRQ requests altogether. 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[edit | edit source]

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
           STA $D020            ; change border colour to yellow

           LDX #$90             ; empty loop to do nothing for just under half a millisecond
Pause      DEX
           BNE Pause

           LDA #$0
           STA $D020            ; change border colour 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.

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[edit | edit source]

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 its "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
           AND #%11011111
           STA $D011

           LDA #<Irq2            ; set interrupt vectors to the second interrupt service routine at Irq2
           STA $0314
           LDA #>Irq2
           STA $0315

           LDA #$0
           STA $D012            ; next interrupt will occur at line no. 0

           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.

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 bitmap screen mode
           ORA #%00100000
           STA $D011

           LDA #<Irq             ; set interrupt vectors back to the first interrupt service routine at Irq
           STA $0314
           LDA #>Irq
           STA $0315

           LDA #210
           STA $D012            ; next interrupt will occur at line no. 210

           ASL $D019            ; acknowledge the interrupt by clearing the VIC's interrupt flag

           JMP $EA81            ; jump into shorter ROM routine to only restore registers from the stack etc

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.

Links[edit | edit source]

WP-W11.png Wikipedia: Raster_interrupt