processor 6502 include "vcs.h" include "macro.h" include "xmacro.h" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This example demonstrates a scene with a full-screen ; playfield, and two sprites overlapping it. This takes more ; CPU time, so our kernel operates in 4-line chunks. ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; seg.u Variables org $80 PFPtr word ; pointer to playfield data PFIndex byte ; offset into playfield array PFCount byte ; lines left in this playfield segment YPos0 byte ; Y position of player 0 sprite XPos0 byte ; X position of player 0 sprite YPos1 byte ; Y position of player 1 sprite XPos1 byte ; X position of player 1 sprite ; pointers to bitmap and color tables SpritePtr0 word ColorPtr0 word SpritePtr1 word ColorPtr1 word ; temporary values for kernel YP0 byte ; Y counter for player 0 YP1 byte ; Y counter for player 1 Temp byte Bitp0 byte Bitp1 byte Colp0 byte Colp1 byte tmpPF0 byte tmpPF1 byte tmpPF2 byte SpriteHeight equ 16 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; seg Code org $f000 Start CLEAN_START Data0 ; set up pointers to playfield and sprites lda #Data0 sta PFPtr+1 lda #Frame0 sta SpritePtr0+1 lda #ColorFrame0 sta ColorPtr0+1 lda #Frame0 sta SpritePtr1+1 lda #ColorFrame0 sta ColorPtr1+1 ; set up initial positions lda #242 sta YPos0 lda #200 sta YPos1 lda #38 sta XPos0 sta XPos1 lda #1 sta VDELP0 ; updates to GRP0 will be delayed NextFrame VERTICAL_SYNC ; Set up VBLANK timer TIMER_SETUP 37 lda #$88 sta COLUBK ; bg color lda #$5b sta COLUPF ; fg color lda #$68 sta COLUP0 ; player color lda #1 sta CTRLPF ; symmetry lda #72 sta PFIndex ; reset playfield offset ; Set temporary Y counter and set horizontal position lda YPos0 sta YP0 ; yp0 = temporary counter lda YPos1 sta YP1 ; yp0 = temporary counter lda XPos0 ldx #0 jsr SetHorizPos lda XPos1 ldx #1 jsr SetHorizPos sta WSYNC sta HMOVE ; gotta apply HMOVE ; Wait for end of VBLANK TIMER_WAIT lda #0 sta VBLANK SLEEP 31 ; so timing analysis works out KernelLoop ; Phase 0: Fetch PF0 byte jsr DrawSprites ldy PFIndex ; no more playfield? beq NoMoreLines ; exit loop dey lda (PFPtr),y ; load PF0 sty PFIndex sta tmpPF0 ; Phase 1: Fetch PF1 byte jsr DrawSprites ldy PFIndex dey lda (PFPtr),y ; load PF1 sty PFIndex sta tmpPF1 ; Phase 2: Fetch PF2 byte jsr DrawSprites ldy PFIndex dey lda (PFPtr),y ; load PF2 sty PFIndex sta tmpPF2 ; Phase 3: Write PF0/PF1/PF2 registers jsr DrawSprites lda tmpPF0 sta PF0 lda tmpPF1 sta PF1 lda tmpPF2 sta PF2 ; Go to next scanline jmp KernelLoop NoMoreLines ; Set up overscan timer TIMER_SETUP 27 lda #2 sta VBLANK jsr MoveJoystick TIMER_WAIT jmp NextFrame ; DrawSprite subroutine called by kernel DrawSprites ; Fetch sprite 0 values lda #SpriteHeight ; height in 2xlines sec isb YP0 ; INC yp0, then SBC yp0 bcs DoDraw0 ; inside bounds? lda #0 ; no, load the padding offset (0) DoDraw0 tay ; -> Y lda (ColorPtr0),y ; color for both lines sta Colp0 ; -> colp0 lda (SpritePtr0),y ; bitmap for first line sta GRP0 ; -> [GRP0] (delayed due to VDEL) ; Fetch sprite 1 values lda #SpriteHeight ; height in 2xlines sec isb YP1 ; INC yp0, then SBC yp0 bcs DoDraw1 ; inside bounds? lda #0 ; no, load the padding offset (0) DoDraw1 tay ; -> Y lda (ColorPtr1),y ; color for both lines tax lda (SpritePtr1),y ; bitmap for first line tay ; WSYNC and store sprite values lda Colp0 sta WSYNC sty GRP1 ; GRP0 is also updated due to VDELP0 flag stx COLUP1 sta COLUP0 ; Return to caller rts SetHorizPos sta WSYNC ; start a new line bit 0 ; waste 3 cycles sec ; set carry flag DivideLoop sbc #15 ; subtract 15 bcs DivideLoop ; branch until negative eor #7 ; calculate fine offset asl asl asl asl sta RESP0,x ; fix coarse position sta HMP0,x ; set fine offset rts ; return to caller ; Read joystick movement and apply to object 0 MoveJoystick ; Move vertically ; (up and down are actually reversed since ypos starts at bottom) ldx YPos0 lda #%00100000 ;Up? bit SWCHA bne SkipMoveUp cpx #175 bcc SkipMoveUp dex SkipMoveUp lda #%00010000 ;Down? bit SWCHA bne SkipMoveDown cpx #254 bcs SkipMoveDown inx SkipMoveDown stx YPos0 ; Move horizontally ldx XPos0 lda #%01000000 ;Left? bit SWCHA bne SkipMoveLeft cpx #1 bcc SkipMoveLeft dex SkipMoveLeft lda #%10000000 ;Right? bit SWCHA bne SkipMoveRight cpx #153 bcs SkipMoveRight inx SkipMoveRight stx XPos0 rts ; Bitmap data "standing" position Frame0 .byte #0 .byte #%01101100;$F6 .byte #%00101000;$86 .byte #%00101000;$86 .byte #%00111000;$86 .byte #%10111010;$C2 .byte #%10111010;$C2 .byte #%01111100;$C2 .byte #%00111000;$C2 .byte #%00111000;$16 .byte #%01000100;$16 .byte #%01111100;$16 .byte #%01111100;$18 .byte #%01010100;$18 .byte #%01111100;$18 .byte #%11111110;$F2 .byte #%00111000;$F4 ; Color data for each line of sprite ColorFrame0 .byte #$FF; .byte #$F6; .byte #$86; .byte #$86; .byte #$86; .byte #$C2; .byte #$C2; .byte #$C2; .byte #$C2; .byte #$16; .byte #$16; .byte #$16; .byte #$18; .byte #$18; .byte #$18; .byte #$F2; .byte #$F4; ; Epilogue org $fffc .word Start .word Start