raster_routines.asm

For our subroutine InitRasterIRQ we begin by clearing the interrupt here first in the variable (INT_CONTROL – $DC0D (56333). Then we set bit 1 to enable the interrupt for the variable (VIC_INTERRUPT_CONTROL – $D01A (53274). Then we set the first raster at line 16.

InitRasterIRQ

sei ; stop all interrupts
lda PROC_PORT
lda #$7f ; disable cia #1 generating timer irqs
sta INT_CONTROL ; which are used by the system to flash cursor, etc.
lda #$01 ; tell the VIC we want to generate raster irqs
;=============================================================================== 
; ENABLE MASK INTERRUPT
;=============================================================================== 
sta VIC_INTERRUPT_CONTROL
lda #$10 ; number of the rasterline we want the IRQ to occur at
sta VIC_RASTER_LINE ; we used this for WaitFrame, remember? Reading gives the current
 

Set bit 7 in the variable (VIC_SCREEN_CONTROL – $D011 (53265). This tests the negative flag and provides a way to slow down the graphics display until the raster scan is in the vertical blanking interval and the display is no longer being drawn on the screen.

After this we locate our first interrupt at IrqTopScreen and restore the interrupts to ensure the system is back to default settings.

lda VIC_SCREEN_CONTROL ; Fetch the VIC_SCREEN_CONTROL 
and #%01111111 ; mask the surrounding bits 
; or in the value we want to set the MSB (Most significant bit) 
; in this case, it's cleared 
sta VIC_SCREEN_CONTROL ; set the irq vector to point to our routine 
lda #<IrqTopScreen
sta $0314 
lda #>IrqTopScreen 
sta $0315 ; Acknowlege any pending cia timer interrupts 
; just to be 100% safe 
lda $dc0d 
lda $dd0d 
cli ; turn interrupts back on 
rts

In this section we stop all interrupts from running and set the I/O registers are visible. Turn on all bits in $DC0D (56333). Then we enable the raster compare IRQ in $D01A (53274). Finally we set a call to confirm other active CIA Timer interrupts.

;--------------------------------------------------------------------------------------------------- 
; RELEASE RASTER IRQs 
;---------------------------------------------------------------------------------------------------

ReleaseRasterIRQ

sei ; stop all interrupts 
lda #$37 ; make sure the IO regs at $dxxx 
sta $01 ; are visible 
lda #$ff ; enable cia #1 generating timing irq's 
sta $dc0d 
lda #$00 ; no more raster IRQ's 
sta $d01a 
lda #$31 
sta $0314 
lda #$ea 
sta $0315 
lda $dc0d ; acknowlege any pending cia timer interrupts 
lda $dd0d 
cli 
rts

Now we set another interrupt within the routine IrqTopScreen. As usual we turn off all the other running interrupts (keyboard, screen, disk operation (I/O), etc. and then set a new call to an interrupt called IrqGlitchCatcher at scan line 191.

IrqTopScreen

sei ; acknowledge VIC irq
lda $D019
sta $D019 ; install glitch irq
lda #<IrqGlitchCatcher
sta $0314
lda #>IrqGlitchCatcher
sta $0315
lda #$BF
sta $D012

Within the first part of this interrupt routine we check the high byte of the variable (CURRENT_SCREEN + 1) and then compare it to the variable (SCREEN2_MEM). If it matches we set Screen 1 to active using the register (VIC_MEMORY_CONTROL – $D018 (53272), which manages the character set.

@start 
lda CURRENT_SCREEN + 1 ; Hi byte of the current screen 
cmp #>SCREEN2_MEM ; compare to start of Screen2 
beq @screen2

Now we begin to set Character Set 1 using bit 1 passed to the variable (VIC_MEMORY_CONTROL). The routine then exits here.

However, if Screen 2 is active then bit 1 is set and stored in the variable (VIC_SCREEN_MEMORY_CONTROL).

; SET CHARACTER SET 1 AND 2 
lda #%00000010 ; Set VIC to Screen0, Charset 1 
sta VIC_MEMORY_CONTROL ; 53272 
jmp @scroll @screen2
lda #%00010010 ; Set VIC to Screen1, Charset 1 
sta VIC_MEMORY_CONTROL

In this routine area we load the contents of the variable (VIC_SCREEN_CONTROL_Y), mask out bits 3-7, and turn on bits 0-2 for our Y scroll values within the variable (SCROLL_COUNT_Y) and save the new results back into (VIC_SCREEN_CONTROL_Y).

@scroll 
;------------------------------------------------------ SCREEN HARDWARE SCROLL (VERT) 
lda VIC_SCREEN_CONTROL_Y ; Take the current values 
and #%11111000 ; mask out the scroll values 
ora SCROLL_COUNT_Y ; or in the scroll count (bits 0-2 - y scroll value) 
sta VIC_SCREEN_CONTROL_Y ; save the updated info in the registers
 

For the final part of this routine we get the value in variable (VIC_SCREEN_CONTROL_X), mask out bits 3-7 (lower 4 bits), turn on bits 0-2 in the variable (SCROLL_COUNT_X) and save the new result in the variable (VIC_SCREEN_CONTROL_X).

Then we call the subroutine (ReadJoystick) to get our joystick values and the subroutine (JoyButton) to check any fire button status and eventually exit the interrupt here.

;=============================================================================== 
; HORIZONTAL FINE SCROLLING 
;=============================================================================== 
;------------------------------------------------------ SCREEN HARDWARE SCROLL (HORIZ) 
lda VIC_SCREEN_CONTROL_X ; Take the current values (Set at IrqScoreBoard)
and #%11111000 ; mask out the lower 4 bits (screen cols and scroll)
ora SCROLL_COUNT_X ; Or in the scroll count (bits 0-2 - x scroll value)
sta VIC_SCREEN_CONTROL_X
; Save the updated info 
;------------------------------------------------------ TIMERS AND SYSTEM UPDATES
jsr ReadJoystick
jsr JoyButton 
cli 
jmp $ea31
rts

In this stage we set the interrupt and point it to the raster routine IrqGlitchCatcher. Then  we set the raster scan at line 199.

;===============================================================================
; IRQ GLITCHCATHER ;===============================================================================
; Force badline, black out character garble from scroll, and adjust timing glitches
;---------------------------------------------------------------------------------------------------

IrqGlitchCatcher

sei ; acknowledge VIC irq 
lda $D019 
sta $D019 ; install scroller irq 
lda #
sta $0314
lda #>IrqScoreBoard 
sta $0315 ; nr of rasterline we want the NEXT irq to occur at 
lda #$c7 ; Scoreboard appears 8 raster lines after the glitch catcher 
sta $D012

So for this raster routine we check the frames in the variable (SCROLL_COUNT_Y) which manages the vertical scrolling of the screen. It checks between frames 0-7 to ensure accurate timing. Individual frames receive several nop (No operation) calls to allow for more wasted time.

lda SCROLL_COUNT_Y 
beq @fr_0 
cmp #7 
beq @fr_7 
cmp #1 
beq @fr_1 
cmp #2 
beq @fr_2 
cmp #3 
beq @fr_3 
cmp #4 
beq @fr_4 
cmp #5 
beq @fr_5 
cmp #6 
beq @fr_6 
jmp @start
@fr_1 
;nop 
@fr_2 
nop 
nop 
@fr_3 
nop 
nop 
nop 
@fr_4 
nop 
@fr_5 
nop 
nop 
@fr_6 
nop 
nop 
nop 
nop 
nop 
@fr_7 
nop 
@fr_0

The next routine below sets bits 2, 5, and 6 within the variable (VIC_MEMORY_CONTROL – $D018 (53272).

;=============================================================================== 
; CHARACTER SET GENERATOR ROM 
;===============================================================================

@start

lda #%01100100 ; Set VIC to Screen 6, Charset 2 
sta VIC_MEMORY_CONTROL

Now we set the vertical scroll at 7 to force a bad line for every frame using the variable (VIC_SCREEN_CONTROL_Y – $D011 (53265). Bits 0,1,2,4, and 6  are enabled here.

Bits 0-2 = Fine scroll display vertically by X scan lines (0-7)

Bit 4 = Blank the entire screen to the same color as the border (0=blank)

Bit 6 = Enable extended color text mode (1=enable)

The next variable at (VIC_SCREEEN_CONTROL_X – $d016 (53270) uses bits4, 6, and 7 to enable the multicolor and the extended background mode.

Bit 4 = Blanks the entire screen to the same color as the border (0=blank)

Bit 6 = Enable extended color text mode (1=enable)

Bit 7 = High Bit (Bit 8) of raster compare register at 53266 ($D012)

;=============================================================================== 
; EXTENDED BACKGROUND MODE  
;===============================================================================
lda #%01010111 ; Set Y to scroll 7 to force badline to every frame 
sta VIC_SCREEN_CONTROL_Y ; set extended background mode 
;=============================================================================== 
; HORIZONTAL FINE SCROLLING
;===============================================================================
lda #%11010000 
sta VIC_SCREEN_CONTROL_X ; X scroll to 0 / multicolor on / 38 cols
; If you set multicolor AND extended background 
; you get an illegal mode that sets everything to 
; black  
cli 
jmp $ea31

Our next interrupt pointer manages the routine IrqScoreBoard, which points to the next interrupt in succession, which is EnemyTimer. The raster scan here begins here at line 10.

IrqScoreBoard

sei ; acknowledge VIC irq 
lda $D019 
sta $D019 ; install scroller irq 

lda #<EnemyTimer
sta $0314 
lda #>EnemyTimer 
sta $0315
; nr of rasterline we want the NEXT irq to occur at 

lda #$A 
sta $D012

The routine here uses variable (VIC_SCREEN_CONTROL_Y) to set the Y scroll to active (bit 4) and variable (VIC_SCREEN_CONTROL_X) to set X as active (bits 4,6, and 7) for our horizontal control setting. See the following bit description to learn about the purpose of these.

;===============================================================================
; VERTICAL SCREEN SCROLLING 
;===============================================================================
lda #%00010000 ; Restore to Y Scroll = 0
sta VIC_SCREEN_CONTROL_Y ; Be aware that :
; bit #0-2 = vertical scroll 
; bit #3 = screen height (0 = 24 rows) 
; bit #4 = screen on/off 
; bit #5 = text/bitmap (0 = text) 
; bit #6 = extended background on/off 
; bit #7 = read/write current raster line bit #8 
; So '3' is the default vert scroll location 
;=============================================================================== 
; HORIZONTAL FINE SCROLLING 
;===============================================================================
lda #%11010000
sta VIC_SCREEN_CONTROL_X ; Set screen to default 
; bit #3 controls screen width (0 = 38 cols) 
; bit #4 controls multicolor (0 = off)
cli
jmp $ea31
rts

After this we enemy the routine WaterAnimation at scan line 85 and the routine PlayerTimer using raster scan line 96. Here is some information about each:

ENEMY_TIMER = masks the variable (ENEMY_SPEED) to get a set value, and its cleared afterward.

PLAYER_TIMER = masks the variable (PLAYER_SPEED) to get a set value, which also clears after use.

EnemyTimer

jsr WaterAnimation
sei ; acknowledge VIC irq
lda $D019
sta $D019 ; install scroller irq
lda #<PlayerTimer
sta $0314
lda #>PlayerTimer
sta $0315

; nr of rasterline we want the NEXT irq to occur at

lda #$55
sta $D012
dec ENEMY_TIMER
lda ENEMY_TIMER
and ENEMY_SPEED
bne @end_enemytimer
lda #0
sta ENEMY_TIMER
@end_enemytimer
cli
jmp $ea31

PlayerTimer

sei ; acknowledge VIC irq
lda $D019
sta $D019 ; install scroller irq
lda #<IrqTopScreen
sta $0314 
lda #>IrqTopScreen
sta $0315
; nr of rasterline we want the NEXT irq to occur at
lda #$60
sta $D012
dec PLAYER_TIMER
lda PLAYER_TIMER 
and PLAYER_SPEED
bne @end_playertimer
lda #0
sta PLAYER_TIMER
@end_playertimer
cli
jmp $ea31