In our previous post in this series, we went over the environment within which our 2600 game must live. It is a harsh, barren environment by today's standards, which makes this all the more bitchin'. Anyway, let's take a quick look at what we've covered:
Our game will be running through a 1.19Mhz 6507 CPU. This CPU can direct commands to a custom Atari chip – the Television Interface Adapter (TIA) – which we use for updating the display, receiving collision notifications, and initiating audio. The TIA, indeed the entire system, is clocked so that it is in sync with the television's raster scan process. Our code should, therefore, break into at least the following two parts: initialization and main loop. The main loop must consist of at least the vertical sync, followed by vertical blank, followed by display scans, and then overscan. Using the 2600 programming guide noted in the previous post (from now on, Stella programming guide, or just Stella), we should actually be able to piece something called a 'kernel' (see Stella, pg.1 bottom) together:
processor 6502
include "vcs.h" ; DASM pseudo-op to include mnemonics for TIA / RIOT registers
seg
org $F000 ; our ROM starts at the beginning of the second 4K block
label_Reset
LDA #150
STA COLUBK ; set out background color to a nice blue
; --------------------------- our "kernel" starts here
label_Frame
; --------------------------- do the v-sync (Stella, §3.3)
label_Vsync
LDA #2
STA VSYNC ; enable D1 bit at VSYNC to start vertical sync
STA WSYNC
STA WSYNC
STA WSYNC ; our 3 scanlines
LDA #0
STA VSYNC ; disable D1 but to finish vertical sync
; --------------------------- do the v-blank (Stella, §3.3)
label_Vblank
LDA #2
STA VBLANK ; enable D1 bit at VBLANK to start vertical blank
repeat 37
STA WSYNC ; do 37 scanlines using DASM "REPEAT" pseudo-op
repend
LDA #0
STA VBLANK ; disable D1 bit at VBLANK to finish vertical blank
; --------------------------- do the picture lines (Stella, §TELEVISION PROTOCOL)
label_Picture
repeat 192
STA WSYNC ; do 192 scanlines using DASM "REPEAT" pseudo-op
repend
; --------------------------- do the scanlines (Stella, §TELEVISION PROTOCOL)
label_Overscan
repeat 30
STA WSYNC ; do 30 scanlines using DASM "REPEAT" pseudo-op
repend
; --------------------------- do it all over again, 60 times per second!
JMP label_Frame
org $FFFA
.word label_Reset ; NMI
.word label_Reset ; RESET
.word label_Reset ; IRQ
end
Copy and paste this code into SciTE and run it (see the first post on setting up our IDE). You should see something like the following (click to see if full-size image):
There's several important things to go over here. First, the most important following an IDE build/run environment:
Using Stella as the emulator to test your game is extremely helpful just for the info you see in the picture. This info's display is toggled using the Alt-L combo. Notice we have what we want: 262 scanlines (3 vertical-sync, 37 vertical-blank, 192 display, 30 overscan) at 60 frames per second, thereby designating an NTSC display. This is the very first point of troubleshooting, and why this series will be focusing for the long run on NTSC development. I could have easily chosen PAL instead. What's important is that those number match exactly our target television's specs, because that means we are meeting the proper machine cycles per scanline, scanlines per frame, and vertical-sync and –blank criteria; in other words, our code is humming nicely along with the TV's scanning.
Now try altering the picture lines code with:
; --------------------------- do the picture lines (Stella, §TELEVISION PROTOCOL)
label_Picture
repeat 34 ; 4 NOPs ( = 8 cycles ) short of the 76 cycles for a complete scan line
NOP ; = 2 cycles
repend
repeat 191
STA WSYNC ; do 192 scanlines using DASM "REPEAT" pseudo-op
repend
Stella should now display:
Hmmm…we're off. We know why, of course, but this “technique” has so far helped me out many, many times simply when I've counted cycles wrong (we'll get to this).
I'll leave off here with some code to play around with. Run it, then look over the code to see the changes from our first simple “kernel” at the beginning of this post. Try to figure out what's going on, and review the Stella guide. Next post, I'll get into a bit more with troubleshooting our code and breaking down our simple kernel.
processor 6502
include "vcs.h" ; DASM pseudo-op to include mnemonics for TIA / RIOT registers
seg
org $F000 ; our ROM starts at the beginning of the second 4K block
atColor = $80
label_Reset
LDA #255
STA atColor
; --------------------------- our "kernel" starts here
label_Frame
; --------------------------- do the v-sync (Stella, §3.3)
label_Vsync
LDA #2
STA VSYNC ; enable D1 bit at VSYNC to start vertical sync
STA WSYNC
STA WSYNC
STA WSYNC ; our 3 scanlines
LDA #0
STA VSYNC ; disable D1 but to finish vertical sync
; --------------------------- do the v-blank (Stella, §3.3)
label_Vblank
LDA #2
STA VBLANK ; enable D1 bit at VBLANK to start vertical blank
repeat 36
STA WSYNC
repend
DEC atColor
LDY atColor
LDX #192
STA WSYNC
LDA #0
STA VBLANK ; disable D1 bit at VBLANK to finish vertical blank
; --------------------------- do the picture lines (Stella, §TELEVISION PROTOCOL)
label_Picture
INY
STY COLUBK
STA WSYNC ; do 192 scanlines using DASM "REPEAT" pseudo-op
DEX
CPX #0
BNE label_Picture
; --------------------------- do the scanlines (Stella, §TELEVISION PROTOCOL)
label_Overscan
repeat 30
STA WSYNC ; do 30 scanlines using DASM "REPEAT" pseudo-op
repend
; --------------------------- do it all over again, 60 times per second!
JMP label_Frame
org $FFFA
.word label_Reset ; NMI
.word label_Reset ; RESET
.word label_Reset ; IRQ
end
~ZagNut