2018-08-13 22:17:36 +00:00
|
|
|
|
2016-12-16 01:21:51 +00:00
|
|
|
processor 6502
|
|
|
|
include "vcs.h"
|
|
|
|
include "macro.h"
|
|
|
|
include "xmacro.h"
|
|
|
|
|
2018-10-01 01:07:45 +00:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;
|
|
|
|
; 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.
|
|
|
|
;
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
2016-12-16 01:21:51 +00:00
|
|
|
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
|
2018-08-26 13:19:09 +00:00
|
|
|
|
2016-12-16 01:21:51 +00:00
|
|
|
Data0
|
2018-08-26 13:19:09 +00:00
|
|
|
; set up pointers to playfield and sprites
|
2016-12-16 01:21:51 +00:00
|
|
|
lda #<Data0
|
|
|
|
sta PFPtr
|
|
|
|
lda #>Data0
|
|
|
|
sta PFPtr+1
|
|
|
|
lda #<Frame0
|
|
|
|
sta SpritePtr0
|
|
|
|
lda #>Frame0
|
|
|
|
sta SpritePtr0+1
|
|
|
|
lda #<ColorFrame0
|
|
|
|
sta ColorPtr0
|
|
|
|
lda #>ColorFrame0
|
|
|
|
sta ColorPtr0+1
|
|
|
|
lda #<Frame0
|
|
|
|
sta SpritePtr1
|
|
|
|
lda #>Frame0
|
|
|
|
sta SpritePtr1+1
|
|
|
|
lda #<ColorFrame0
|
|
|
|
sta ColorPtr1
|
|
|
|
lda #>ColorFrame0
|
|
|
|
sta ColorPtr1+1
|
2018-08-26 13:19:09 +00:00
|
|
|
; set up initial positions
|
2016-12-16 01:21:51 +00:00
|
|
|
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
|
2018-08-26 13:19:09 +00:00
|
|
|
TIMER_SETUP 27
|
2016-12-16 01:21:51 +00:00
|
|
|
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
|
|
|
|
|
2019-03-26 00:39:53 +00:00
|
|
|
;; Bitmap data "standing" position
|
|
|
|
;;{w:8,h:17,brev:1,flip:1};;
|
2016-12-16 01:21:51 +00:00
|
|
|
Frame0
|
2019-03-26 00:39:53 +00:00
|
|
|
.byte #%0
|
2016-12-16 01:21:51 +00:00
|
|
|
.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
|
2019-03-26 00:39:53 +00:00
|
|
|
;; Color data for each line of sprite
|
|
|
|
;;{pal:"vcs"};;
|
2016-12-16 01:21:51 +00:00
|
|
|
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;
|
2019-03-26 00:39:53 +00:00
|
|
|
;;
|
2016-12-16 01:21:51 +00:00
|
|
|
; Epilogue
|
|
|
|
org $fffc
|
|
|
|
.word Start
|
|
|
|
.word Start
|