2

I was following this tutorial on Commodore 64 timer interrupts and tried to replicate it (except all I was planning on doing was changing the border color.) I noticed that my interrupt only occurs once, and never triggers again. I don't understand why. (Just as an aside, when I first tested this, I also had a scanline IRQ set up and it worked fine, except it also halted the main program and only interrupts could run!)

Here's a minimal reproducible example. The border color changes from light blue to light gray and never again (only one inc $D020 gets executed.) I tried changing the timer values a bit but it doesn't make a difference, the IRQ only happens once. What did I miss?

    org $0801       

    ;INIT CODE
    db $0E,$08,$0A,$00,$9E,$20,$28,$32,$30,$36,$34,$29,$00,$00,$00  
    
    sei
    
    lda #%01010010
    STA $DC0F
    ;TIMER B COUNTS TIMER A UNDERFLOW
    ;LOAD START VALUE INTO TIMER,
    ;INDICATE TIMER UNDERFLOW ON PORT B BIT 7
    

    LDA #$FF
    STA $DC04
    
    LDA #$00    
    STA $DC05       ;LOAD TIMER 1 WITH VALUE $00FF
    
    LDX #$01
    
    STX $DC06
    DEX
    STX $DC07       ;LOAD TIMER 2 WITH VALUE $0001
    
    
    LDA #<IRQ
    STA $0314
    LDA #>IRQ
    STA $0315       ;LOAD IRQ VECTOR WITH IRQ ROUTINE ADDR.
    
    LDA #%00010001
    STA $DC0E       ;TURN ON TIMER 1 AND LOAD THE START VALUE
    

    CLI
    
    
forever:
    jmp forever
    
    
IRQ:
    LDA #%01111111
    STA $DC0D   
    LDA $DC0D   ;IRQ ACK
    
    INC $D020   ;UPTICK THE BORDER COLOR
    
    
    pla
    tay
    pla
    tax
    pla
    rti
5
  • Without going deep, I can't see any setting for timer A control, like having it reload every time used. Similar no check if it's really a timer interrupt - after all, IRQ is as well hit once per frame for the jiffy clock - which as well doesn't get served from your routine. Last, but for sure not least, what are the values you're using? It seems the effective interrupt rate is every 255 cycles. Quite short. That's close to 4000 times per second. With the right harmonic this may quite well look like no change at all.
    – Raffzahn
    Jan 1, 2022 at 3:09
  • Originally I had Timer A at $03FC and Timer B at $FFFF and it made no difference. Also, if it's the only IRQ enabled doesn't that mean by default it has to be from the timer? I tried reloading the timer in the IRQ handler body but no luck there either Jan 1, 2022 at 4:07
  • Did you miss to push the register values at the start of the interrupt handler? Jan 3, 2022 at 20:10
  • @MartinRosenau The KERNAL does that for you. Jan 3, 2022 at 20:37
  • I'm a VIC-20 coder (3.5K RAM should be enough for anybody) so I don't know if the C64 CIAs work similarly to the VIAs I'm familiar with, but on the VIC you have to acknowledge the current IRQ from VIA #2 before the next will hit the CPU. This is done by reading the VIA #2 timer #1 countdown lo-byte latch (e.g. BIT $9124). Jan 6, 2022 at 16:05

1 Answer 1

2

In your interrupt service routine, you are turning all CIA interrupt sources off:

LDA #%01111111
STA $DC0D

Writing to $DC0D is writing to a mask register. To quote the 6526 datasheet:

When writing to the MASK register, if bit 7 (SET/CLEAR) of data written is a ZERO, any mask bit written with a on will be cleared, while those mask bits written with a zero will be unaffected. If bit 7 of the data written is a ONE, any mask bit written with a one will be set, while those mask bits written with a zero will be unaffected.

To enable timer B interrupt, bit #1 has to be set, so the value to be written into the mask register should be #%10000010 Furthermore, this should better be done in the setup routine, not the interrupt service routine.

This then gives you interrupt calls every 256 cycles, I think this was your intention:

enter image description here

You must log in to answer this question.

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