vcs: added chap 8, 11, 12, 13 examples

This commit is contained in:
Steven Hugg 2019-07-19 21:50:53 -04:00
parent d9b40a566d
commit e852fd27a6
6 changed files with 479 additions and 0 deletions

View File

@ -130,6 +130,11 @@ TODO:
- support NES_HEADER_16K?
- PPU/TIA register write visualization
- NES crt should mark raster pos when debugging
- JSNES
- doesn't support hiding >8 sprites
- doesn't do sprite zero test right
- doesn't do clip right
- doesn't do b/w tint
- vcs
- need Chapter 8 example?
- vcs sound continues when paused

View File

@ -0,0 +1,103 @@
processor 6502
include "vcs.h"
include "macro.h"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; We can draw a color sprite by setting two registers
; on every scanline:
; GRP0 (the bitmap) and COLUP0 (the player color).
; There's a separate lookup table for each.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SpriteHeight equ 8
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Variables segment
seg.u Variables
org $80
YPos .byte
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Code segment
seg Code
org $f000
Start
CLEAN_START
lda #5
sta YPos
NextFrame
lsr SWCHB ; test Game Reset switch
bcc Start ; reset?
; 1 + 3 lines of VSYNC
VERTICAL_SYNC
; 37 lines of underscan
ldx #37
LVBlank sta WSYNC
dex
bne LVBlank
; 192 lines of frame
ldx #192 ; X = 192 scanlines
LVScan
txa ; X -> A
sec ; set carry for subtract
sbc YPos ; local coordinate
cmp #SpriteHeight ; in sprite?
bcc InSprite ; yes, skip over next
lda #0 ; not in sprite, load 0
InSprite
tay ; local coord -> Y
lda Frame0,y ; lookup color
sta WSYNC ; sync w/ scanline
sta GRP0 ; store bitmap
lda ColorFrame0,y ; lookup color
sta COLUP0 ; store color
dex ; decrement X
bne LVScan ; repeat until 192 lines
; 29 lines of overscan
ldx #29
LVOver sta WSYNC
dex
bne LVOver
; total = 262 lines, go to next frame
jmp NextFrame
; Cat-head graphics data
Frame0
.byte #0 ; zero padding, also clears register
.byte #%00111100
.byte #%01000010
.byte #%11100111
.byte #%11111111
.byte #%10011001
.byte #%01111110
.byte #%11000011
.byte #%10000001
; Cat-head color data
ColorFrame0
.byte #0 ; unused (for now)
.byte #$AE
.byte #$AC
.byte #$A8
.byte #$AC
.byte #$8E
.byte #$8E
.byte #$98
.byte #$94
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Epilogue
org $fffc
.word Start ; reset vector
.word Start ; BRK vector

View File

@ -0,0 +1,176 @@
processor 6502
include "vcs.h"
include "macro.h"
include "xmacro.h"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; We're going to set the player's coarse and fine position
; at the same time using a clever method.
; We divide the X coordinate by 15, in a loop that itself
; is 15 cycles long. When the loop exits, we are at
; the correct coarse position, and we set RESP0.
; The accumulator holds the remainder, which we convert
; into the fine position for the HMP0 register.
; This logic is in a subroutine called SetHorizPos.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SpriteHeight equ 8
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Variables segment
seg.u Variables
org $80
XPos .byte
YPos .byte
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Code segment
seg Code
org $f000
Start
CLEAN_START
lda #80
sta YPos
sta XPos
NextFrame
lsr SWCHB ; test Game Reset switch
bcc Start ; reset?
; 1 + 3 lines of VSYNC
VERTICAL_SYNC
; 37 lines of underscan
TIMER_SETUP 37
; move X and Y coordinates w/ joystick
jsr MoveJoystick
; the next two scanlines
; position the player horizontally
lda XPos ; get X coordinate
ldx #0 ; player 0
jsr SetHorizPos ; set coarse offset
sta WSYNC ; sync w/ scanline
sta HMOVE ; apply fine offsets
; it's ok if we took an extra scanline because
; the PIA timer will always count 37 lines
; wait for end of underscan
TIMER_WAIT
; 192 lines of frame
ldx #192 ; X = 192 scanlines
LVScan
txa ; X -> A
sec ; set carry for subtract
sbc YPos ; local coordinate
cmp #SpriteHeight ; in sprite?
bcc InSprite ; yes, skip over next
lda #0 ; not in sprite, load 0
InSprite
tay ; local coord -> Y
lda Frame0,y ; lookup color
sta WSYNC ; sync w/ scanline
sta GRP0 ; store bitmap
lda ColorFrame0,y ; lookup color
sta COLUP0 ; store color
dex ; decrement X
bne LVScan ; repeat until 192 lines
; 29 lines of overscan
TIMER_SETUP 29
TIMER_WAIT
; total = 262 lines, go to next frame
jmp NextFrame
; SetHorizPos routine
; A = X coordinate
; X = player number (0 or 1)
SetHorizPos
sta WSYNC ; start a new line
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 YPos
lda #%00100000 ;Up?
bit SWCHA
bne SkipMoveUp
cpx #2
bcc SkipMoveUp
dex
SkipMoveUp
lda #%00010000 ;Down?
bit SWCHA
bne SkipMoveDown
cpx #183
bcs SkipMoveDown
inx
SkipMoveDown
stx YPos
; Move horizontally
ldx XPos
lda #%01000000 ;Left?
bit SWCHA
bne SkipMoveLeft
cpx #16
bcc SkipMoveLeft
dex
SkipMoveLeft
lda #%10000000 ;Right?
bit SWCHA
bne SkipMoveRight
cpx #153
bcs SkipMoveRight
inx
SkipMoveRight
stx XPos
rts
; Cat-head graphics data
Frame0
.byte #0 ; zero padding, also clears register
.byte #%00111100
.byte #%01000010
.byte #%11100111
.byte #%11111111
.byte #%10011001
.byte #%01111110
.byte #%11000011
.byte #%10000001
; Cat-head color data
ColorFrame0
.byte #0 ; unused (for now)
.byte #$AE
.byte #$AC
.byte #$A8
.byte #$AC
.byte #$8E
.byte #$8E
.byte #$98
.byte #$94
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Epilogue
org $fffc
.word Start ; reset vector
.word Start ; BRK vector

View File

@ -0,0 +1,51 @@
processor 6502
include "vcs.h"
include "macro.h"
include "xmacro.h"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Variables segment
seg.u Variables
org $80
Temp .byte
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Code segment
seg Code
org $f000
Start
CLEAN_START
NextFrame
lsr SWCHB ; test Game Reset switch
bcc Start ; reset?
; 1 + 3 lines of VSYNC
VERTICAL_SYNC
; 37 lines of underscan
TIMER_SETUP 37
TIMER_WAIT
; 192 lines of frame
TIMER_SETUP 192
; draw colors based on timer value
LRainbow
lda INTIM ; load timer
sta COLUBK ; store background
bne LRainbow ; loop until timer == 0
TIMER_WAIT ; timer is already 0, no-op
; 29 lines of overscan
TIMER_SETUP 29
TIMER_WAIT
; total = 262 lines, go to next frame
jmp NextFrame
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Epilogue
org $fffc
.word Start ; reset vector
.word Start ; BRK vector

View File

@ -0,0 +1,140 @@
processor 6502
include "vcs.h"
include "macro.h"
include "xmacro.h"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; We're going to set the player's coarse and fine position
; at the same time using a clever method.
; We divide the X coordinate by 15, in a loop that itself
; is 15 cycles long. When the loop exits, we are at
; the correct coarse position, and we set RESP0.
; The accumulator holds the remainder, which we convert
; into the fine position for the HMP0 register.
; This logic is in a subroutine called SetHorizPos.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SpriteHeight equ 8
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Variables segment
seg.u Variables
org $80
XPos .byte
YPos .byte
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Code segment
seg Code
org $f000
Start
CLEAN_START
lda #5
sta YPos
sta XPos
NextFrame
lsr SWCHB ; test Game Reset switch
bcc Start ; reset?
; 1 + 3 lines of VSYNC
VERTICAL_SYNC
; 35 lines of underscan
ldx #35
LVBlank sta WSYNC
dex
bne LVBlank
; animate X and Y coordinates
; NOTE: when X is too close to the right side,
; we risk using an extra scanline
inc XPos
inc YPos
; the next two scanlines
; position the player horizontally
lda XPos ; get X coordinate
ldx #0 ; player 0
jsr SetHorizPos ; set coarse offset
sta WSYNC ; sync w/ scanline
sta HMOVE ; apply fine offsets
; 192 lines of frame
ldx #192 ; X = 192 scanlines
LVScan
txa ; X -> A
sec ; set carry for subtract
sbc YPos ; local coordinate
cmp #SpriteHeight ; in sprite?
bcc InSprite ; yes, skip over next
lda #0 ; not in sprite, load 0
InSprite
tay ; local coord -> Y
lda Frame0,y ; lookup color
sta WSYNC ; sync w/ scanline
sta GRP0 ; store bitmap
lda ColorFrame0,y ; lookup color
sta COLUP0 ; store color
dex ; decrement X
bne LVScan ; repeat until 192 lines
; 29 lines of overscan
ldx #29
LVOver sta WSYNC
dex
bne LVOver
; total = 262 lines, go to next frame
jmp NextFrame
; SetHorizPos routine
; A = X coordinate
; X = player number (0 or 1)
SetHorizPos
sta WSYNC ; start a new line
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
; Cat-head graphics data
Frame0
.byte #0 ; zero padding, also clears register
.byte #%00111100
.byte #%01000010
.byte #%11100111
.byte #%11111111
.byte #%10011001
.byte #%01111110
.byte #%11000011
.byte #%10000001
; Cat-head color data
ColorFrame0
.byte #0 ; unused (for now)
.byte #$AE
.byte #$AC
.byte #$A8
.byte #$AC
.byte #$8E
.byte #$8E
.byte #$98
.byte #$94
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Epilogue
org $fffc
.word Start ; reset vector
.word Start ; BRK vector

View File

@ -14,8 +14,12 @@ const VCS_PRESETS = [
{id:'examples/vsync.a', chapter:5, name:'Painting on the CRT', title:'Color Bars'},
{id:'examples/playfield.a', chapter:6, name:'Playfield Graphics'},
{id:'examples/sprite.a', chapter:7, name:'Players and Sprites'},
{id:'examples/colorsprites.a', chapter:8, name:'Color Sprites'},
{id:'examples/timing2.a', chapter:9, name:'Fine Positioning', title:'Fine Position'},
{id:'examples/missiles.a', chapter:10, name:'Player/Missile Graphics', title:'Player/Missile'},
{id:'examples/sethorizpos.a', chapter:11, name:'SetHorizPos Routine'},
{id:'examples/piatimer.a', chapter:12, name:'PIA Timer'},
{id:'examples/controls.a', chapter:13, name:'Joysticks'},
{id:'examples/complexscene.a', chapter:15, name:'Complex Scene I'},
{id:'examples/complexscene2.a', chapter:16, name:'Complex Scene II'},
{id:'examples/scoreboard.a', chapter:18, name:'Scoreboard'},