Question

I'm trying to set up a simple raster interrupt handler to change the background color in a given stripe. However, my interrupt handler seems to be called all the time. (the code uses CA65's format)

.include "c64.inc"

ROW = 100

.segment "ZPSAVE"

.segment "STARTUP"

        sei

        ;; Turn off BASIC and KERNAL ROM
        lda #$35
        sta $01

        ;; Flush CIA IRQs
        bit CIA1_ICR
        bit CIA2_ICR

        ;; Turn off CIA interrupts
        lda #%011111111
        sta CIA1_ICR
        sta CIA2_ICR

        ;; Set target raster line
        lda #%01111111
        and VIC_CTRL1
        sta VIC_CTRL1

        lda #ROW
        sta VIC_HLINE

        ;; Enable VIC interrupt
        lda #%00000001
        sta VIC_IMR

        ;; Install interrupt handler
        lda #<isr
        sta $fffe
        lda #>isr
        sta $ffff
        cli

        rts

.macro isr_pre
        pha
        txa
        pha
        tya
        pha
.endmacro

.macro isr_post
        pla
        tay
        pla
        tax
        rti
.endmacro

;;; Acknowledge VIC interrupt
.macro ack_vic
        lda VIC_IRR
        and #$01
        sta VIC_IRR
.endmacro

.proc isr
        isr_pre
        ack_vic

        ;; Uncommenting these lines works around the problem
        ;; lda VIC_HLINE
        ;; cmp #ROW
        ;; bne exit

        lda #1
        sta VIC_BORDERCOLOR
        sta VIC_BG_COLOR0

        ldx #50
:       dex
        bne :-

        lda #0
        sta VIC_BORDERCOLOR
        sta VIC_BG_COLOR0

exit:   isr_post
.endproc

If I comment out the three lines marked as the "workaround" in the above code, then my interrupt handler is called all the time, not just on (the start of) row ROW:

Without workaround

If I uncomment those three lines, then it works, but it's very unstable, I guess because of those same unintended interrupts:

With workaround

Was it helpful?

Solution

I've found several problems with my code as posted above, and fixing all of them fixed the problem:

  1. The bitmask for turning off CIA interrupts was wrong (it was accidentally 9 bits long) -- this is what was causing all those extra interrupt firings...
  2. The ISR postscriptum macro was missing a pla to restore the A register -- this screwed up state royally, so whatever happened with the old code was more-or-less by chance...
  3. The VIC interrupt was not flushed in the interrupt setup code -- so after fixing the previous two problems, now the interrupts were never triggered.
  4. There's nothing to rts to at the end of the setup code, since we turn off kernal and BASIC ROM

So the fixed code is as follows:

.include "c64.inc"

ROW = 100

;;; Acknowledge VIC interrupt
.macro ack_vic
        lda VIC_IRR
        and #$01
        sta VIC_IRR
.endmacro

.segment "ZPSAVE"

.segment "STARTUP"

        sei

        ;; Turn off BASIC and KERNAL ROM
        lda #$35
        sta $01

        ;; Flush CIA IRQs
        bit CIA1_ICR
        bit CIA2_ICR
        ack_vic

        ;; Turn off CIA interrupts
        lda #%01111111
        sta CIA1_ICR
        sta CIA2_ICR

        ;; Set target raster line
        lda #%01111111
        and VIC_CTRL1
        sta VIC_CTRL1

        lda #ROW
        sta VIC_HLINE

        ;; Enable VIC interrupt
        lda #%00000001
        sta VIC_IMR

        ;; Install interrupt handler
        lda #<isr
        sta $fffe
        lda #>isr
        sta $ffff
        cli    
        jmp *

.macro isr_pre
        pha
        txa
        pha
        tya
        pha
.endmacro

.macro isr_post
        pla
        tay
        pla
        tax
        pla
        rti
.endmacro

.proc isr
        isr_pre
        ack_vic

        lda #1
        sta VIC_BORDERCOLOR
        sta VIC_BG_COLOR0

        ldx #50
:       dex
        bne :-

        lda #0
        sta VIC_BORDERCOLOR
        sta VIC_BG_COLOR0

exit:   isr_post
.endproc

This results, as expected, in a solid white stripe. For some unknown reason, the stripe starts at the middle of the screen horizontally, but I guess that'd be one for a separate SO question.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top