.include "../inc/common.i" print_a = $ffd2 SCREEN_RAM = $0400 COLOUR_RAM = $d800 VIC_CTRL_A = $d011 VIC_RASTER_REG = $d012 VIC_CTRL_B = $d016 VIC_MEMORY_CTRL=$d018 VIC_IRQ_FLAG = $d019 IRQ_VECTOR=$314 BORDER_COLOR = $d020 BACKGROUND_COLOR_0 = $d021 SCROLL_DELAY=4 CHARS_PER_LINE = 40 SCROLL_LINE=12 SCROLL_RAM = SCREEN_RAM+(SCROLL_LINE*CHARS_PER_LINE) TOP_BORDER_SCAN_LINES = 50 BLACK = 0 WHITE = 1 RED = 2 CYAN = 3 PURPLE = 4 GREEN = 5 BLUE = 6 YELLOW = 7 ORANGE = 8 BROWN = 9 LIGHT_RED = 10 DARK_GRAY = 11 GRAY = 12 LIGHT_GREEN = 13 LIGHT_BLUE = 14 LIGHT_GRAY = 15 .macro wait_next_raster lda VIC_RASTER_REG : cmp VIC_RASTER_REG beq :- .endmacro .zeropage temp_buff: .res 2 pptr: .res 2 .bss .segment "STARTUP" ;this is what gets put at the start of the file on the C64 .word basicstub ; load address basicstub: .word @nextline .word 2003 .byte $9e .byte <(((init / 1000) .mod 10) + $30) .byte <(((init / 100 ) .mod 10) + $30) .byte <(((init / 10 ) .mod 10) + $30) .byte <(((init ) .mod 10) + $30) .byte 0 @nextline: .word 0 .code init: lda #0 jsr clear_screen lda #DARK_GRAY sta BORDER_COLOR lda #YELLOW sta BACKGROUND_COLOR_0 sei ;disable maskable IRQs 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 #$00 ;this is how to tell at which rasterline we want the irq to be triggered sta VIC_RASTER_REG ldax IRQ_VECTOR stax old_irq jsr set_next_irq_jump cli ;enable maskable interrupts again lda #23 @endless_loop: nop inc $ff inc $400 tsx stx $410 sta $411 ldy #$80 : iny bne :- jmp @endless_loop clear_screen: ldx #$00 lda #$41 : sta SCREEN_RAM,x sta SCREEN_RAM+$100,x sta SCREEN_RAM+$200,x sta SCREEN_RAM+$300,x sta COLOUR_RAM,x sta COLOUR_RAM+$100,x sta COLOUR_RAM+$200,x sta COLOUR_RAM+$300,x dex bne :- rts set_next_irq_jump: inc jump_counter lda jump_counter asl asl load_next_raster_entry: tax lda raster_jump_table,x ;bit 9 of raster to trigger on cmp #$ff bne not_last_entry lda #0 sta jump_counter jmp load_next_raster_entry not_last_entry: ora #$18 ;turn on bits 3 & 4 sta VIC_CTRL_A lda raster_jump_table+1,x ;bits 0..7 of raster to trigger on sta VIC_RASTER_REG lda raster_jump_table+2,x ;LSB of IRQ handler sta IRQ_VECTOR lda raster_jump_table+3,x ;LSB of IRQ handler sta IRQ_VECTOR+1 rts exit_from_irq: jsr set_next_irq_jump jmp_to_original_irq_handler: lda #$ff ;this is the orthodox and safe way of clearing the interrupt condition of the VICII. sta VIC_IRQ_FLAG;if you don't do this the interrupt condition will be present all the time and you end ;up having the CPU running the interrupt code all the time, as when it exists the ;interrupt, the interrupt request from the VICII will be there again regardless of the ;rasterline counter. old_irq = * + 1 ; Placeholder for self-modifying code jmp $ffff raster_irq: ldax #synchronised_irq stax IRQ_VECTOR nop ; waste at least 12 cycles nop ; (up to 64 cycles delay allowed here) nop nop nop nop inc VIC_RASTER_REG ; At this stage, we have already moved to the next line lda #1 sta VIC_IRQ_FLAG ; acknowledge the first raster interrupt cli ; enable interrupts (the second interrupt can now occur) ldy #9 dey bne *-1 ; delay nop ; The second interrupt will occur while executing these nop ; two-cycle instructions. nop nop nop jmp jmp_to_original_irq_handler synchronised_irq: ldx VIC_RASTER_REG nop nop nop nop nop nop nop bit $24 ; 6569, 63 cycles/line cpx VIC_RASTER_REG ; The comparison cycle is executed CYCLES or CYCLES+1 cycles ; after the interrupt has occurred. beq :+ ; Delay by one cycle if $d012 hadn't changed. ; Now exactly CYCLES+3 cycles have passed since the interrupt : ;now got a stable raster nop nop nop nop nop nop nop inc BORDER_COLOR inc BACKGROUND_COLOR_0 ldx #20 @loop: wait_next_raster dex bne @loop dec BORDER_COLOR dec BACKGROUND_COLOR_0 jmp exit_from_irq .data raster_jump_table: ;format: ;offset meaning ; $00 BIT 9 OF RASTER TO TRIGGER ON ($00 if bit 8 =0 , $80 if bit 8 =1) ; $01 BITS 0..7 OF RASTER TO TRIGGER ON ; $02 LSB OF ROUTINE TO JUMP TO ; $03 MSB OF ROUTINE TO JUMP TO ;table needs to end with a single byte $ff ;table needs to be sorted by scanlines ; .byte $0,$01 ; .word scroll_text_irq .byte $0,$81 .word raster_irq ; .byte $0,$80 ; .word raster_irq .byte $ff ;end of list jump_counter: .byte 0 ;-- LICENSE FOR raster.s -- ; The contents of this file are subject to the Mozilla Public License ; Version 1.1 (the "License"); you may not use this file except in ; compliance with the License. You may obtain a copy of the License at ; http://www.mozilla.org/MPL/ ; ; Software distributed under the License is distributed on an "AS IS" ; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the ; License for the specific language governing rights and limitations ; under the License. ; ; The Original Code is ip65. ; ; The Initial Developer of the Original Code is Jonno Downes, ; jonno@jamtronix.com. ; Portions created by the Initial Developer are Copyright (C) 2009 ; Jonno Downes. All Rights Reserved. ; -- LICENSE END --