6

Having disabled BASIC and Kernal routines I set up an IRQ to run the following code when the raster line reaches 200:

.irq1

    inc 53280  // change border colour
    
//  lda #$ff   // clear the VIC2 interrupt condition
//  sta $d019 

    asl $D019  // alternative way to clear the VIC2 interrupt condition

    rti

which works, but I'm having difficulty chaining two IRQ's so that the border has a short band of a single colour. For example, the following does not work:

.irq1

    lda #0
    sta 53280

    lda #120     // this is how to tell at which rasterline we want the irq to be triggered
    sta $d012

    lda #lo(irq2)  // this is how we set up
    sta $fffe           // the address of our interrupt code
    lda #hi(irq2)
    sta $ffff

    asl $D019 

    rti

.irq2

    lda #1
    sta 53280

    lda #100     // this is how to tell at which rasterline we want the irq to be triggered
    sta $d012

    lda #lo(irq1)  // this is how we set up
    sta $fffe           // the address of our interrupt code
    lda #hi(irq1)
    sta $ffff

    asl $D019 

    rti

I thought maybe I had to set the interrupt disable flag sei and then clear it cli again (since I'm altering the interrupt details) but certain combinations of this did not work. Can anyone help with this?

For completion, here is the interrupt set up code as requested by @Retrograde:

    sei

    lda #$7f
    sta $dc0d  // disable timer interrupts which can be generated by the two CIA chips
    sta $dd0d  // the kernal uses such an interrupt to flash the cursor and scan the keyboard, so we better
               // stop it.
               
    lda $dc0d  // by reading this two registers we negate any pending CIA irqs.
    lda $dd0d  // if we don't do this, a pending CIA irq might occur after we finish setting up our irq.
               // we don't want that to happen.

    lda #$01   // this is how to tell the VICII to generate a raster interrupt
    sta $d01a
    
    lda #100     // this is how to tell at which rasterline we want the irq to be triggered
    sta $d012
    
    lda #$1b   // as there are more than 256 rasterlines, the topmost bit of $d011 serves as
    sta $d011  // the 9th bit for the rasterline we want our irq to be triggered.
               // here we simply set up a character screen, leaving the topmost bit 0.

    lda #$35   // we turn off the BASIC and KERNAL rom here
    sta $01    // the cpu now sees RAM everywhere except at $d000-$e000, where still the registers of
               // SID/VICII/etc are visible
               
    lda #lo(irq1)  // this is how we set up
    sta $fffe  // the address of our interrupt code
    lda #hi(irq1)
    sta $ffff

    cli        // enable maskable interrupts again

.infiniteLoop
    jmp infiniteLoop
5

The general principle of what you're doing would seem to be correct.

I would add, though, that unless you're doing anything outside the interrupts except spinning, you would need to save and restore processor registers to ensure the interrupt handlers to not mess with that code.

In fact, that part, outside the interrupt handlers, is what you'd typically refer to as the main loop, these handlers are not loops.

The devil's in the details, so I suggest you post your entire code so that we can see how you set up the raster interrupt and what you do when not in an interrupt.

Here's the full text of a working example:

    sei
    lda #$7f
    sta $dc0d
    sta $dd0d
    lda $dc0d   // ack any pending
    lda $dd0d   // CIA irqs
    lda #$01
    sta $d01a
    lda #100   // scan line of initial irq
    sta $d012
    lda #$1b
    sta $d011
    lda #$35   // mask out BASIC/KERNAL ROMs
    sta $01
    lda #<irq1 // initial irq
    sta $fffe
    lda #>irq1 // vector
    sta $ffff
    cli
spin:
    jmp spin

irq1:   // Note, interrupts are already disabled at this point (CPU does that after saving processor state)

    pha // if you are going to be doing anything outside the irq except spinning
    txa // you need to save CPU register state
    pha
    tya
    pha

    lda #1    // white
    sta $d020
    sta $d021

    lda #120  // scanline of next irq
    sta $d012

    lda #<irq2 // next irq
    sta $fffe
    lda #>irq2 // vector
    sta $ffff

    inc $d019 // acknowledge irq

    pla // restore register state
    tay
    pla
    tax
    pla
    rti // restore processor state and return from irq

irq2:
    pha
    txa
    pha
    tya
    pha

    lda #0    // black
    sta $d020
    sta $d021

    lda #100  // scanline of previous irq
    sta $d012

    lda #<irq1 // previous irq
    sta $fffe
    lda #>irq1 // vector
    sta $ffff

    inc $d019

    pla
    tay
    pla
    tax
    pla
    rti

Showing a white bar on a black screen

1
  • 3
    your code matches my own, and I eventually found out it was in fact my 6502 assembler that was at fault not recognising labels properly. But anyway it's very useful to have your answer here as reference as I wasn't sure of my code in the first place. Thank you. – Pixel Jan 25 at 9:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.