Background change at Raster Location
Moderator: Moderators
- chysn
- Vic 20 Scientist
- Posts: 1204
- Joined: Tue Oct 22, 2019 12:36 pm
- Website: http://www.beigemaze.com
- Location: Michigan, USA
- Occupation: Software Dev Manager
Re: Background change at Raster Location
Let me be clear: The code I provided in the OP is not the right way to do this. It was my first draft. I have another draft, and I'm trying to find it for you. It's not on my SD card for some reason. It was marginally better than the first draft. Ultimately, I didn't use it in my game because the game would sometimes just freeze for seconds at a time, and I didn't really have the time or the remaining memory to diagnose it.
I sort of came to the conclusion that getting a raster split to be totally solid would require more counting than I'll ever be willing to do.
But if I manage to track down my "marginally-better" version, I'll post it here. Maybe I saved it on a different SD card...?
Out of curiosity, does your program have interrupt activities unrelated to the screen that must be processed?
Edit: Damn it all, this is embarrassing. I save everything I do on the VIC, on the basis that I'll never run out of space. Every time I snap the shutter on my DSLR, it takes like three thousand VIC-20s worth of disk space. I'll see if I can reconstruct it from wet memory...
I sort of came to the conclusion that getting a raster split to be totally solid would require more counting than I'll ever be willing to do.
But if I manage to track down my "marginally-better" version, I'll post it here. Maybe I saved it on a different SD card...?
Out of curiosity, does your program have interrupt activities unrelated to the screen that must be processed?
Edit: Damn it all, this is embarrassing. I save everything I do on the VIC, on the basis that I'll never run out of space. Every time I snap the shutter on my DSLR, it takes like three thousand VIC-20s worth of disk space. I'll see if I can reconstruct it from wet memory...
VIC-20 Projects: wAx Assembler, TRBo: Turtle RescueBot, Helix Colony, Sub Med, Trolley Problem, Dungeon of Dance, ZEPTOPOLIS, MIDI KERNAL, The Archivist, Ed for Prophet-5
WIP: MIDIcast BASIC extension
he/him/his
WIP: MIDIcast BASIC extension
he/him/his
Re: Background change at Raster Location
I used Markos raster routine in my Mario Demo.
I found it worked pretty much out-of-the box, although as Mike mentioned it wastes a few cycles. Suggest starting with a new program, then incorporating your code into his.
Mine has four stable horizontal splits (one of which does nothing).
As you can see, it's doing smooth scrolling, music and sprite rendering (very much a WIP at the moment) concurrently.
I found it worked pretty much out-of-the box, although as Mike mentioned it wastes a few cycles. Suggest starting with a new program, then incorporating your code into his.
Mine has four stable horizontal splits (one of which does nothing).
As you can see, it's doing smooth scrolling, music and sprite rendering (very much a WIP at the moment) concurrently.
-
- Vic 20 Devotee
- Posts: 253
- Joined: Fri Mar 19, 2010 1:40 pm
Re: Background change at Raster Location
Do you have a cc65 version of the routine or did you use the same compiler that Marko uses?
Could I see JUST the code you used?
Could I see JUST the code you used?
(mod: quote repaired)beamrider wrote: ↑Sat Jun 06, 2020 3:09 pm I used Markos raster routine in my Mario Demo.
I found it worked pretty much out-of-the box, although as Mike mentioned it wastes a few cycles. Suggest starting with a new program, then incorporating your code into his.
Mine has four stable horizontal splits (one of which does nothing).
As you can see, it's doing smooth scrolling, music and sprite rendering (very much a WIP at the moment) concurrently.
-
- Vic 20 Devotee
- Posts: 253
- Joined: Fri Mar 19, 2010 1:40 pm
Re: Background change at Raster Location
I am just starting an unexpanded game. Yes, it will do other interrupt activities for moving objects around.
chysn wrote: ↑Sat Jun 06, 2020 1:32 pm Let me be clear: The code I provided in the OP is not the right way to do this. It was my first draft. I have another draft, and I'm trying to find it for you. It's not on my SD card for some reason. It was marginally better than the first draft. Ultimately, I didn't use it in my game because the game would sometimes just freeze for seconds at a time, and I didn't really have the time or the remaining memory to diagnose it.
I sort of came to the conclusion that getting a raster split to be totally solid would require more counting than I'll ever be willing to do.
But if I manage to track down my "marginally-better" version, I'll post it here. Maybe I saved it on a different SD card...?
Out of curiosity, does your program have interrupt activities unrelated to the screen that must be processed?
Edit: Damn it all, this is embarrassing. I save everything I do on the VIC, on the basis that I'll never run out of space. Every time I snap the shutter on my DSLR, it takes like three thousand VIC-20s worth of disk space. I'll see if I can reconstruct it from wet memory...
Re: Background change at Raster Location
Here you go. I've prepped it without testing so take your chances. As I mentioned it's not very efficient at the moment. I will convert to Mike's routine eventually when I get the other higher priority pieces sorted.vicassembly wrote: ↑Sat Jun 06, 2020 4:00 pm Do you have a cc65 version of the routine or did you use the same compiler that Marko uses?
Could I see JUST the code you used?
Just call InstallRaterSplit from your game start and then add you hooks to the various points. If you only want one split, you can revert to the stock timing from Markos original.
Code: Select all
.segment "CODE"
; http://www.retrocomputing.net/parts/commodore/vic20/docs/6561c.txt
; ------------------------------ exports -----------------------------
.global InstallRaterSplit
;------------------------------ Constants ---------------------
NTSC = 1
PAL = 2
DEFAULT_HSPLIT_DELAY = 37
;SYSTEM = NTSC ; 6560-101: 65 cycles per raster line, 261 lines
SYSTEM = PAL ; 6561-101: 71 cycles per raster line, 312 lines
.if SYSTEM & PAL
LINES = 312
CYCLES_PER_LINE = 71
.endif
.if SYSTEM & NTSC
LINES = 261
CYCLES_PER_LINE = 65
.endif
SPLIT_BASELOCATION = 111 + 08 ; Start at 3rd split....
BANDS = 4
TIMER_VALUE = (LINES / BANDS * CYCLES_PER_LINE) - 2
splitCounter: .byte 0
hSplitDelay: .byte DEFAULT_HSPLIT_DELAY
; IRQ Handler -------------------------------------------------------------------------------
irq:
; 38 to 45 IRQ prep cycles delay at this stage
lda $9114 ; get the NMI timer A value
; (42 to 49 cycles delay at this stage)
cmp #8 ; are we more than 7 cycles ahead of time?
bcc @0
pha ; yes, spend 8 extra cycles
pla
and #7 ; and reset the high bit
@0:
cmp #4
bcc @1
bit $24 ; waste 4 cycles
and #3
@1:
cmp #2 ; spend the rest of the cycles
bcs *+2
bcs *+2
lsr
bcs *+2 ; now it has taken 82 cycles from the beginning of the IRQ
@effect:
lda splitCounter
inc splitCounter
and #3
cmp #0;
beq @split0
cmp #1
beq @split1
cmp #2
beq @bottomarea
cmp #3
beq @revertColor
JMP $EB15
@split0: ; ~25% of way down lines after top of screen
lda #59
sta 36879
jmp $EABF ; - if kb scan needed each frame
;jmp $EB15 ; - if no kb scan needed
@split1: ; ~50% of way down lines after top of screen
lda #42
sta 36879
JMP $EB15;
@bottomarea: ; ~75% of way down lines after top of screen
lda #25
sta 36879
; setup off-screen scroll area
JMP $EB15;
@revertColor:; ~100% = VBlank
lda #8
sta 36879
jmp $EB15 ; return to normal IRQ
@loop:
dey
bpl @loop
rts
; Initialisation of raster splits-----------------------------------------------------------------------------
InstallRaterSplit:
lda #3
sta splitCounter
lda #$7f
sta $912e ; disable and acknowledge interrupts
sta $912d
sta $911e ; disable NMIs (Restore key)
;synchronize with the screen
sync:
ldx #SPLIT_BASELOCATION ; wait for this raster line (times 2)
@0:
cpx $9004
bne @0 ; at this stage, the inaccuracy is 7 clock cycles
; the processor is in this place 2 to 9 cycles
; after $9004 has changed
ldy #9
bit $24
@1:
ldx $9004
txa
bit $24
.if SYSTEM & PAL
ldx #24
.elseif SYSTEM & NTSC
bit $24
ldx #21
.endif
dex
bne *-1 ; first spend some time (so that the whole
cmp $9004 ; loop will be 2 raster lines)
bcs *+2 ; save one cycle if $9004 changed too late
dey
bne @1
; now it is fully synchronized
; 6 cycles have passed since last $9004 change
; and we are on line 2(116+9)=250
;initialize the timers
timers:
lda #$40 ; enable Timer A free run of both VIAs
sta $911b
sta $912b
lda #<TIMER_VALUE
ldx #>TIMER_VALUE
sta $9116 ; load the timer low byte latches
sta $9126
.if SYSTEM & PAL
ldy #7 ; make a little delay to get the raster effect to the
dey ; right place
bne *-1
nop
nop
.endif
.if SYSTEM & NTSC
ldy #6
dey
bne *-1
bit $24
.endif
stx $9125 ; start the IRQ timer A
; 6560-101: 65 cycles from $9004 change
; 6561-101: 77 cycles from $9004 change
ldy #10 ; spend some time (1+5*9+4=55 cycles)
dey ; before starting the reference timer
bne *-1
stx $9115 ; start the reference timer
pointers:
lda #<irq ; set the raster IRQ routine pointer
sta $314
lda #>irq
sta $315
lda #$c0
sta $912e ; enable Timer A underflow interrupts
rts ; return
Re: Background change at Raster Location
btw... it would be nice to have some kind of code-generator for Mike's routine, where you enter the number of splits, PAL/NTSC and desired scan-lines and it outputs a CA65 compatible file.
- Mike
- Herr VC
- Posts: 5130
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Re: Background change at Raster Location
I posted a link to the source of my routine already in the first page of the thread here, but to ease things, here's the source quoted:vicassembly wrote:3. I looked for a printout of Mike's stable routine and could not find it. Mike: Could you help me with a text version of it or point me to the right place?
Code: Select all
DIM code 511
:
ntsc=TRUE
:
cycles=&4243:line=17:phase=21:delay=21:pos=5
IF NOT ntsc THEN cycles=&5686:line=30:phase=88:delay=23:pos=1
:
aux_extbrd_1=&3C00
bck_intbrd_1=&3D00
aux_extbrd_2=&3E00
bck_intbrd_2=&3F00
:
FOR pass=4 TO 7 STEP 3
P%=&3B00:O%=code
[OPT pass
.Init
SEI
LDA #Server MOD 256:STA &0314
LDA #Server DIV 256:STA &0315
LDA #cycles MOD 256:STA &9124
LDY #line
.Init_00
CPY &9004:BNE Init_00:INY:INY
.Init_01
CPY &9004:BNE Init_01:JSR Init_06
INY:CPY &9004:BEQ Init_02:NOP:NOP
.Init_02
JSR Init_06:NOP
INY:CPY &9004:BEQ Init_03:BIT &24
.Init_03
JSR Init_06:NOP
INY:CPY &9004:BNE Init_04
.Init_04
LDX #pos
.Init_05
DEX:BNE Init_05
]
IF ntsc THEN [OPT pass:NOP:NOP:]
[OPT pass
LDA #cycles DIV 256:STA &9125
CLI
RTS
.Init_06
LDX #delay
.Init_07
DEX:BNE Init_07
]
IF NOT ntsc THEN [OPT pass:NOP:]
[OPT pass
RTS
.Server
CLD:SEC:LDA #phase:SBC &9124
CMP #10:BCC Server_00:JMP &EABF
.Server_00
STA Server_01+1
.Server_01
BCC Server_01
LDA #&A9
LDA #&A9
LDA #&A9
LDA #&A9
LDA #&A5
NOP
LDA &FB:PHA
LDX &900F
LDY #0
.Server_02
JMP Frame1
.Frame1
LDA &900E:EOR aux_extbrd_1,Y:AND #&0F:EOR aux_extbrd_1,Y:STA &FB
LDA aux_extbrd_1,Y:EOR bck_intbrd_1,Y:AND #&0F:STX &900F:EOR bck_intbrd_1,Y:TAX
LDA &FB:STA &900E:STX &900F:]:IF NOT ntsc THEN [OPT pass:CMP (&00,X):]
[OPT pass:LDA bck_intbrd_1,Y:STA &900F:NOP:INY:CPY #&C1:BCC Frame1
LDX #Frame2 MOD 256
LDY #Frame2 DIV 256
JMP Exit
.Frame2
LDA &900E:EOR aux_extbrd_2,Y:AND #&0F:EOR aux_extbrd_2,Y:STA &FB
LDA aux_extbrd_2,Y:EOR bck_intbrd_2,Y:AND #&0F:STX &900F:EOR bck_intbrd_2,Y:TAX
LDA &FB:STA &900E:STX &900F:]:IF NOT ntsc THEN [OPT pass:CMP (&00,X):]
[OPT pass:LDA bck_intbrd_2,Y:STA &900F:NOP:INY:CPY #&C1:BCC Frame2
LDX #Frame1 MOD 256
LDY #Frame1 DIV 256
.Exit
STX Server_02+1
STY Server_02+2
PLA:STA &FB
JMP &EABF
]
NEXT
Also, a stable raster does not merely "not flicker around vertically for one or two raster lines". It SITS on the raster beam and is also exactly defined in the horizontal position, accurate to a single CPU cycle!
If you just want to have three or more regions on screen, vertically stacked, with different background colours, that can be done without the necessity to use Marko's or my routine:
- Setup timer 1 to fire once per frame at a given raster line one or two rasters before the first change is supposed to happen. This interrupt provides the base position from which all other interrupts are derived.
- In the interrupt routine, first check whether timer 1 or timer 2 fired.
- If timer 1 fired, enter a loop to wait for the correct raster line, "nudge" the CPU with NOPs into the side border, do the background change, and setup timer 2 to fire one or two raster lines *before* the 2nd register change should happen.
- If timer 2 fired, and the 2nd register change is bound to happen, again enter a loop to wait for the correct raster line, "nudge" the CPU, do the background change and setup timer 2 again to fire one or two raster lines before the 3rd register change.
- timer 2 fires, and 3rd register change? Again, enter a loop for the correct raster line, CPU NOP "nudge", background change, eventually setup of timer 2 for further interrupts.
Re: Background change at Raster Location
Using Markos routine as I posted above I got 4 irqs each of which were stable and didn't wander around although some required a few NOPs to get the colour change off screen but I didn't have to poll. I can shift them all up or down based relative to the first split.
- Mike
- Herr VC
- Posts: 5130
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Re: Background change at Raster Location
That method then only works for equidistant vertical splits.beamrider wrote:Using Markos routine as I posted above I got 4 irqs each of which were stable and didn't wander around although some required a few NOPs to get the colour change off screen but I didn't have to poll. I can shift them all up or down based relative to the first split.
And, as I said, for just laying out a few vertical regions, both Marko's and my routine are completely over the top.
I use my routine, when I need to split colour registers several times within a single raster, necessarily over a span of several rasters (192 for the height of a MINIGRAFIK bitmap in my example). There, I split the background/border register for a new colour during horizontal beam flyback, at the left edge of the display window, at the right edge of the display window and last, I prepare the auxiliary colour for the next raster before the horizontal flyback comes.
Especially, the changes at the left and right edge of the display window need to be done cycle exact. One cycle off and you're half a character wrong! There's still a one hires pixel difference, but that's due to hardware reasons in the pixel serializer of the VIC chip and nothing can be done to correct this.
Re: Background change at Raster Location
Isn't the most important things how long it takes to synchronise? With your simple approach where you suggested setting an IRQ 2 lines prior, won't this be 140 cycles or so? Markos routine is fixed at 82 cycles.
- Mike
- Herr VC
- Posts: 5130
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Re: Background change at Raster Location
If you want different sized regions, then Marko's method may need to waste a lot more than either 140 or 82 cycles to wait from the 'nearest' interrupt above up to a given colour change.beamrider wrote:Isn't the most important things how long it takes to synchronise? With your simple approach where you suggested setting an IRQ 2 lines prior, won't this be 140 cycles or so? Markos routine is fixed at 82 cycles.
And, again, the stabilization for cycle-exactness is absolutely unnecessary for the task of just stacking some different coloured regions vertically.
If, for whatever reasons, you want to do two or more distinct raster spans, that additionally are supposed to be stable (in the sense of Marko's or my routine), you'd need to do the IRQ jitter compensation for each of them anew. It is already difficult enough to start a timer at a given cycle-exact position (which is the first thing necessary to get the whole thing working, but normally is only done once, at the setup of the interrupt), the IRQ jitter compensation is critically dependent on which of the raster spans you are using, but would need to be the first thing to be done when entering the IRQ server. But you can't just reuse the same jitter compensation for non-equidistant interrupts, as they're likely to use different offsets for the branch calculation of the NOP slide.
- Mike
- Herr VC
- Posts: 5130
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Re: Background change at Raster Location
Here's a blueprint of how I would implement the interrupt server using the method I laid out above:
If you use VICE to build the whole routine to your specification (i.e. colour changes at certain Y-positions), be aware that certain VICE revisions suffer from regression bugs in the VIA implementation. Especially the implementation of timer 2 unfortunately is bugged in those.
Code: Select all
.IRQ
LDA $912D
AND #$40
BEQ IRQ_00
LDA #$00
STA State ; reset State to 0 if timer 1 fired
.IRQ_00
LDY State
INC State
STY $900F ; <- Only used during development to see where each interrupt
; happens. You can remove it, when everything works.
LDA Raster,Y
.IRQ_01
CMP $9004
BNE IRQ_01 ; sync to given raster line
LDX Wait,Y
.IRQ_02
DEX
BNE IRQ_02 ; "nudge" workload into right side border or horizontal sync.
; the real workload starts here. Note the change of $9004 in IRQ_01 happens
; just a few cycles before the display windows starts (on PAL) or even in the
; middle of the raster line (on NTSC), so you'll have to position the IRQ well
; before the wanted raster (at least two 'double'-lines above), wait for
; (double-)raster minus 1, and finally, "nudge" the workload to happen in the
; right border or horizontal sync before the wanted raster.
;
; As this routine isn't fully stabilized, the accuracy will be within 7 cycles
; ($9004 wait) +/- 2 cycles (5 cycle DEX loop), which should be sufficient to
; even hide border colour changes.
LDA Colour,Y
STA $900F
; unless this is the last timer 2 interrupt for the frame, (re-)start timer 2
; by loading the time into it when it's supposed to fire next.
CPY #xx ; "xx" is the number of vertical interrupts, minus 1.
BEQ IRQ_03
LDA Timer2Lo,Y
STA $9128
LDA Timer2Hi,Y
STA $9129 ; use the interrupt "display" of STY $900F to place the next
; timer 2 interrupt two (double-)lines above where the next
; colour change is supposed to happen.
.IRQ_03
CPY #00
BEQ IRQ_04
JMP $EB18 ; timer 2 interrupts just return to the foreground process.
.IRQ_04
JMP $EABF ; the timer 1 interrupt calls the KERNAL IRQ routine to
; process the keyboard. The KERNAL also clears the timer 1
; interrupt in the VIA IFR.
;
; This interrupt should not happen at an arbitrary Y position,
; rather at one, where the next (timer 2) IRQ is supposed to
; have the biggest distance to. This is supposed to give the
; keyboard scan routine enough time (~40 rasters) to do its
; work when a key is pressed.
- Mike
- Herr VC
- Posts: 5130
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Re: Background change at Raster Location
The blueprint proved fully functional with just a few changes. Here's a small teaser:


-
- Vic 20 Devotee
- Posts: 253
- Joined: Fri Mar 19, 2010 1:40 pm
Re: Background change at Raster Location
Mike:
First of all, THANK you for your time. When I saw your reply with the algorithm I told my wife that I feel so lost and inadequate with understanding this stuff. She smiled and guffawed at me.
Your nice screen print is what I want...... I really want to learn so I am going to ask questions.
"Setup timer 1 to fire once per frame at a given raster line one or two rasters before the first change is supposed to happen. This interrupt provides the base position from which all other interrupts are derived."
I see your words and I even see the code that you gave me. I simply don't comprehend this. Set timer 1 up to fire once per frame one or two rasters before? I guess I don't understand timers? How do timers work? Is that what this code does?
.IRQ
LDA $912D
AND #$40
BEQ IRQ_00
LDA #$00
STA State ; reset State to 0 if timer 1 fired
.IRQ_00
I looked at my memory map and it says "this bit is set by an expiration of timer 1 and reset when a read of timer usb or write of timer 1 msb takes place."
"In the interrupt routine, first check whether timer 1 or timer 2 fired."
It appears that this is what you are checking above? I have no idea. When you say interrupt are you speaking of the IRQ interrupt that hits and goes to vector $0314/5?
"If timer 1 fired, enter a loop to wait for the correct raster line, "nudge" the CPU with NOPs into the side border, do the background change, and setup timer 2 to fire one or two raster lines *before* the 2nd register change should happen.
If timer 2 fired, and the 2nd register change is bound to happen, again enter a loop to wait for the correct raster line, "nudge" the CPU, do the background change and setup timer 2 again to fire one or two raster line before the 3rd register change.
timer 2 fires, and 3rd register change? Again, enter a loop for the correct raster line, CPU NOP "nudge", background change, eventually setup of timer 2 for further interrupts."
I am so lost by this. How is timer 1 fired? What does that mean? I get that it should be fired prior to a given raster line. I am getting frustrated by my lack of understanding.
Same questions for timer 2.
Sigh... I need an education on this. Can I pay for a Skype lesson?
.
I could probably look at your vice code and convert that to a CC65 routine. I don't even know how to enter code in vice but that is not the issue.
I'm delving into things that are brand new.
First of all, THANK you for your time. When I saw your reply with the algorithm I told my wife that I feel so lost and inadequate with understanding this stuff. She smiled and guffawed at me.
Your nice screen print is what I want...... I really want to learn so I am going to ask questions.
"Setup timer 1 to fire once per frame at a given raster line one or two rasters before the first change is supposed to happen. This interrupt provides the base position from which all other interrupts are derived."
I see your words and I even see the code that you gave me. I simply don't comprehend this. Set timer 1 up to fire once per frame one or two rasters before? I guess I don't understand timers? How do timers work? Is that what this code does?
.IRQ
LDA $912D
AND #$40
BEQ IRQ_00
LDA #$00
STA State ; reset State to 0 if timer 1 fired
.IRQ_00
I looked at my memory map and it says "this bit is set by an expiration of timer 1 and reset when a read of timer usb or write of timer 1 msb takes place."
"In the interrupt routine, first check whether timer 1 or timer 2 fired."
It appears that this is what you are checking above? I have no idea. When you say interrupt are you speaking of the IRQ interrupt that hits and goes to vector $0314/5?
"If timer 1 fired, enter a loop to wait for the correct raster line, "nudge" the CPU with NOPs into the side border, do the background change, and setup timer 2 to fire one or two raster lines *before* the 2nd register change should happen.
If timer 2 fired, and the 2nd register change is bound to happen, again enter a loop to wait for the correct raster line, "nudge" the CPU, do the background change and setup timer 2 again to fire one or two raster line before the 3rd register change.
timer 2 fires, and 3rd register change? Again, enter a loop for the correct raster line, CPU NOP "nudge", background change, eventually setup of timer 2 for further interrupts."
I am so lost by this. How is timer 1 fired? What does that mean? I get that it should be fired prior to a given raster line. I am getting frustrated by my lack of understanding.
Same questions for timer 2.
Sigh... I need an education on this. Can I pay for a Skype lesson?

I could probably look at your vice code and convert that to a CC65 routine. I don't even know how to enter code in vice but that is not the issue.
I'm delving into things that are brand new.
Re: Background change at Raster Location
Best home work is to read the 6522 datasheet. There are details in there such as the order of writing to the 16 bit timer registers and interrupt enabling that just aren't obvious from looking at code.
In short you load the timer register with a value and when it crosses from 0>FFFF it flags an event. If that event is defined to cause a CPU interrupt then one is raised. Depending on which VIA it is this is either an IRQ or an NMI.
The tricky bit with raster interrupts is that the cycles to set up the timer and those needed to reach the interrupt handler code are significant.
In short you load the timer register with a value and when it crosses from 0>FFFF it flags an event. If that event is defined to cause a CPU interrupt then one is raised. Depending on which VIA it is this is either an IRQ or an NMI.
The tricky bit with raster interrupts is that the cycles to set up the timer and those needed to reach the interrupt handler code are significant.