

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
[…] subroutine (InitRasterIRQ) is used to get the interrupts going. It specifically manages the screen scroll values, screen […]
[…] SetupLevel SetupCollision RoutinesGeneral RoutinesPlayer SetupRaster RoutinesScreen RoutinesScrolling RoutinesSprite […]