!cpu 6510 ; NEON RIFT ; Raster bands, eight sine-orbiting sprites, a split fine scroller and a ; three-voice SID sequence. All state touched by the demo is restored on Q. ; Self-starting BASIC line: 10 SYS2061 * = $0801 !word basic_end !word 10 !byte $9e !text "2061" !byte 0 basic_end: !word 0 * = $080d GETIN = $ffe4 CHROUT = $ffd2 start: jsr save_state lda #0 sta $d020 sta $d021 jsr show_splash lda #147 jsr CHROUT jsr initialize_demo main_loop: lda #250 jsr wait_raster jsr read_controls lda quit_flag beq continue_demo jmp exit continue_demo: lda paused bne render_frame jsr update_motion lda music_muted bne render_frame jsr update_music render_frame: jsr draw_raster_frame jmp main_loop save_state: lda $d020 sta old_border lda $d021 sta old_background lda $d015 sta old_sprite_enable lda $d016 sta old_d016 lda $d01c sta old_multicolor lda $d025 sta old_sprite_mc0 lda $d026 sta old_sprite_mc1 lda $d010 sta old_sprite_msb ldx #0 save_positions: lda $d000,x sta old_positions,x inx cpx #16 bne save_positions ldx #0 save_colors: lda $d027,x sta old_sprite_colors,x lda $07f8,x sta old_sprite_pointers,x inx cpx #8 bne save_colors ldx #0 save_sid: lda $d400,x sta old_sid,x inx cpx #25 bne save_sid rts initialize_demo: lda #0 sta $d020 sta $d021 sta $d010 sta $d01c sta motion_phase sta motion_tick sta palette sta paused sta music_muted sta quit_flag sta scroll_tick sta scroll_position sta music_tick sta music_step lda #2 sta motion_speed lda #7 sta scroll_fine jsr copy_sprite jsr prepare_screen lda #$ff sta $d015 lda #6 sta $d025 lda #14 sta $d026 ldx #0 sprite_setup_loop: lda #$c0 sta $07f8,x lda sprite_colors,x sta $d027,x inx cpx #8 bne sprite_setup_loop jsr initialize_sid jsr update_sprites rts copy_sprite: ldx #0 copy_sprite_loop: lda orb_sprite,x sta $3000,x inx cpx #64 bne copy_sprite_loop rts prepare_screen: ldx #0 clear_pages: lda #32 sta $0400,x sta $0500,x sta $0600,x lda #1 sta $d800,x sta $d900,x sta $da00,x inx bne clear_pages ldx #0 clear_last_page: lda #32 sta $0700,x lda #1 sta $db00,x inx cpx #232 bne clear_last_page ldx #0 draw_stars: lda star_positions_lo,x sta $fb lda star_positions_hi,x sta $fc ldy #0 txa and #1 beq use_dot lda #42 bne store_star use_dot: lda #46 store_star: sta ($fb),y inx cpx #28 bne draw_stars ldx #0 seed_scroller: lda #32 sta $07c0,x lda #7 sta $dbc0,x inx cpx #40 bne seed_scroller rts read_controls: jsr GETIN beq controls_done cmp #81 bne control_color lda #1 sta quit_flag rts control_color: cmp #67 bne control_mute inc palette lda palette and #3 sta palette jmp controls_done control_mute: cmp #77 bne control_pause lda music_muted eor #1 sta music_muted bne mute_music jsr initialize_sid jmp controls_done mute_music: jsr silence_sid jmp controls_done control_pause: cmp #32 bne control_speed_one lda paused eor #1 sta paused bne pause_sound lda music_muted bne controls_done jsr initialize_sid jmp controls_done pause_sound: jsr silence_sid jmp controls_done control_speed_one: cmp #49 bne control_speed_two lda #4 sta motion_speed jmp controls_done control_speed_two: cmp #50 bne control_speed_three lda #2 sta motion_speed jmp controls_done control_speed_three: cmp #51 bne controls_done lda #1 sta motion_speed controls_done: rts update_motion: inc motion_tick lda motion_tick cmp motion_speed bcc update_scroll lda #0 sta motion_tick inc motion_phase lda motion_phase and #63 sta motion_phase jsr update_sprites update_scroll: inc scroll_tick lda scroll_tick cmp #2 bcc motion_done lda #0 sta scroll_tick dec scroll_fine lda scroll_fine and #7 sta scroll_fine cmp #7 bne motion_done jsr shift_scroller motion_done: rts update_sprites: ldx #0 sprite_motion_loop: stx object_index txa asl asl asl clc adc motion_phase and #63 tax lda sine_x,x sta position_temp ldx object_index txa asl tay lda position_temp sta $d000,y ldx object_index txa asl asl asl clc adc motion_phase clc adc #16 and #63 tax lda sine_y,x sta position_temp ldx object_index txa asl tay iny lda position_temp sta $d000,y ldx object_index inx cpx #8 bne sprite_motion_loop rts shift_scroller: ldx #0 scroll_shift_loop: lda $07c1,x sta $07c0,x inx cpx #39 bne scroll_shift_loop ldy scroll_position lda scroll_message,y bne insert_scroll_char ldy #0 sty scroll_position lda scroll_message insert_scroll_char: ; The message is stored as portable ASCII. The VIC-II character screen ; uses screen codes, where uppercase A-Z are 1-26 rather than 65-90. ; Convert explicitly instead of relying on the assembler's active ; conversion table. cmp #65 bcc store_scroll_char cmp #91 bcs store_scroll_char and #$1f store_scroll_char: sta $07e7 inc scroll_position lda palette asl tax lda scroller_colors,x ldx #0 color_scroller: sta $dbc0,x inx cpx #40 bne color_scroller rts initialize_sid: jsr silence_sid lda #$08 sta $d405 lda #$88 sta $d406 lda #0 sta $d402 lda #8 sta $d403 lda #$04 sta $d40c lda #$a8 sta $d40d lda #$02 sta $d413 lda #$84 sta $d414 lda #$00 sta $d417 lda #$0f sta $d418 rts update_music: inc music_tick lda music_tick cmp #6 bcc music_done lda #0 sta music_tick ldx music_step lda #0 sta $d404 sta $d40b sta $d412 lda lead_notes,x tay lda note_lo,y sta $d400 lda note_hi,y sta $d401 lda #$41 sta $d404 lda bass_notes,x tay lda note_hi,y lsr sta $d408 lda note_lo,y ror sta $d407 lda #$11 sta $d40b lda drum_steps,x beq no_drum lda #$35 sta $d40e lda #$18 sta $d40f lda #$81 sta $d412 no_drum: inc music_step lda music_step and #15 sta music_step music_done: rts silence_sid: lda #0 sta $d404 sta $d40b sta $d412 sta $d418 rts draw_raster_frame: ; Keep the KERNAL IRQ from interrupting a color change halfway through a ; raster line. It is enabled again before returning to the main loop. sei lda #45 jsr wait_raster lda old_d016 and #$f8 sta $d016 lda palette asl asl asl tax stx palette_base ldx #0 raster_band_loop: stx band_index lda raster_lines,x jsr wait_raster ldx band_index txa clc adc palette_base tay lda raster_colors,y sta $d021 ldx band_index inx cpx #8 bne raster_band_loop lda #232 jsr wait_raster lda #0 sta $d021 lda old_d016 and #$f8 ora scroll_fine sta $d016 cli rts wait_raster: wait_raster_line: cmp $d012 bne wait_raster_line wait_raster_leave: cmp $d012 beq wait_raster_leave rts show_splash: lda #splash_text sta $fc ldy #0 print_splash: lda ($fb),y beq wait_for_space jsr CHROUT inc $fb bne print_splash inc $fc jmp print_splash wait_for_space: jsr GETIN cmp #32 bne wait_for_space rts exit: jsr silence_sid ldx #0 restore_sid: lda old_sid,x sta $d400,x inx cpx #25 bne restore_sid lda old_sprite_enable sta $d015 lda old_d016 sta $d016 lda old_multicolor sta $d01c lda old_sprite_mc0 sta $d025 lda old_sprite_mc1 sta $d026 lda old_sprite_msb sta $d010 ldx #0 restore_positions: lda old_positions,x sta $d000,x inx cpx #16 bne restore_positions ldx #0 restore_sprite_data: lda old_sprite_colors,x sta $d027,x lda old_sprite_pointers,x sta $07f8,x inx cpx #8 bne restore_sprite_data lda old_border sta $d020 lda old_background sta $d021 lda #147 jsr CHROUT rts splash_text: !byte 147,13,13,13 !byte 154 !text " NEON RIFT" !byte 13,13 !byte 5 !text " RASTER LIGHT, SPRITES AND SID MUSIC" !byte 13,13,13 !byte 153 !text " CONTROLS" !byte 13,13 !text " " !byte 158 !text "1-3" !byte 5 !text " SPEED " !byte 158 !text "C" !byte 5 !text " COLOR " !byte 158 !text "M" !byte 5 !text " MUSIC" !byte 13 !text " " !byte 158 !text "SPACE" !byte 5 !text " PAUSE " !byte 158 !text "Q" !byte 5 !text " QUIT" !byte 13,13,13 !byte 5 !text " HTTPS://C64.P20.DEV" !byte 13,13 !byte 152 !text " RELEASED 16 OCTOBER 2026" !byte 13,13,13 !byte 158 !text " PRESS SPACE TO START" !byte 0 ; Shared 24x21 single-color sprite: a ringed neon orb. orb_sprite: !byte $00,$18,$00,$00,$7e,$00,$01,$ff,$80,$03,$c3,$c0 !byte $07,$81,$e0,$0f,$00,$f0,$1e,$18,$78,$1c,$3c,$38 !byte $38,$7e,$1c,$38,$ff,$1c,$79,$ff,$9e !byte $38,$ff,$1c,$38,$7e,$1c,$1c,$3c,$38,$1e,$18,$78 !byte $0f,$00,$f0,$07,$81,$e0,$03,$c3,$c0,$01,$ff,$80 !byte $00,$7e,$00,$00,$18,$00,$00 sine_x: !byte 136,145,154,163,172,181,189,197,204,211,217,223,228,232,235,238 !byte 239,240,239,238,235,232,228,223,217,211,204,197,189,181,172,163 !byte 154,145,136,127,118,109,101,93,86,79,73,67,62,58,55,52 !byte 51,50,51,52,55,58,62,67,73,79,86,93,101,109,118,127 sine_y: !byte 126,132,138,144,150,156,161,166,171,175,179,182,185,187,189,190 !byte 190,190,189,187,185,182,179,175,171,166,161,156,150,144,138,132 !byte 126,120,114,108,102,96,91,86,81,77,73,70,67,65,63,62 !byte 62,62,63,65,67,70,73,77,81,86,91,96,102,108,114,120 raster_lines: !byte 56,78,100,122,144,166,188,210 raster_colors: !byte 6,11,4,14,3,13,1,13 !byte 0,9,2,8,7,1,7,8 !byte 0,6,14,3,1,3,14,6 !byte 0,11,12,15,1,15,12,11 sprite_colors: !byte 3,14,1,13,7,10,8,2 scroller_colors: !byte 3,14,7,10,13,1,8,2 note_lo: !byte $c4,$22,$81,$e1,$4b,$b8,$2a,$a1 note_hi: !byte $10,$13,$15,$18,$1b,$1e,$22,$26 lead_notes: !byte 0,2,4,2,5,4,2,1,0,2,4,6,5,4,2,1 bass_notes: !byte 0,0,0,0,3,3,3,3,5,5,5,5,3,3,1,1 drum_steps: !byte 1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0 scroll_message: !text " NEON RIFT RASTER LIGHT MEETS EIGHT ORBITING SPRITES AND THREE VOICES OF SID GREETINGS FROM C64.P20.DEV " !byte 0 star_positions_lo: !byte <($0400+2*40+2),<($0400+5*40+7),<($0400+8*40+12),<($0400+11*40+17),<($0400+14*40+22),<($0400+17*40+27),<($0400+20*40+32) !byte <($0400+3*40+37),<($0400+6*40+4),<($0400+9*40+9),<($0400+12*40+14),<($0400+15*40+19),<($0400+18*40+24),<($0400+21*40+29) !byte <($0400+4*40+34),<($0400+7*40+6),<($0400+10*40+11),<($0400+13*40+16),<($0400+16*40+21),<($0400+19*40+26),<($0400+22*40+31) !byte <($0400+2*40+36),<($0400+8*40+5),<($0400+14*40+15),<($0400+20*40+25),<($0400+6*40+35),<($0400+12*40+10),<($0400+18*40+30) star_positions_hi: !byte >($0400+2*40+2),>($0400+5*40+7),>($0400+8*40+12),>($0400+11*40+17),>($0400+14*40+22),>($0400+17*40+27),>($0400+20*40+32) !byte >($0400+3*40+37),>($0400+6*40+4),>($0400+9*40+9),>($0400+12*40+14),>($0400+15*40+19),>($0400+18*40+24),>($0400+21*40+29) !byte >($0400+4*40+34),>($0400+7*40+6),>($0400+10*40+11),>($0400+13*40+16),>($0400+16*40+21),>($0400+19*40+26),>($0400+22*40+31) !byte >($0400+2*40+36),>($0400+8*40+5),>($0400+14*40+15),>($0400+20*40+25),>($0400+6*40+35),>($0400+12*40+10),>($0400+18*40+30) star_rows: !byte 2,5,8,11,14,17,20,3,6,9,12,15,18,21,4,7,10,13,16,19,22,2,8,14,20,6,12,18 star_cols: !byte 2,7,12,17,22,27,32,37,4,9,14,19,24,29,34,6,11,16,21,26,31,36,5,15,25,35,10,30 motion_phase: !byte 0 motion_tick: !byte 0 motion_speed: !byte 0 object_index: !byte 0 position_temp: !byte 0 palette: !byte 0 palette_base: !byte 0 band_index: !byte 0 scroll_tick: !byte 0 scroll_fine: !byte 0 scroll_position: !byte 0 music_tick: !byte 0 music_step: !byte 0 music_muted: !byte 0 paused: !byte 0 quit_flag: !byte 0 old_border: !byte 0 old_background: !byte 0 old_sprite_enable: !byte 0 old_d016: !byte 0 old_multicolor: !byte 0 old_sprite_mc0: !byte 0 old_sprite_mc1: !byte 0 old_sprite_msb: !byte 0 old_positions: !fill 16,0 old_sprite_colors: !fill 8,0 old_sprite_pointers: !fill 8,0 old_sid: !fill 25,0