Tao Te KaChing
Workin' the cash register of the Great Tao

Programming the Atari 2600, and Me - Part 3

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):

kernel_0

There's several important things to go over here.  First, the most important following an IDE build/run environment:

stella-framerate

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:

stella-framerate2

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

,,,,,,,,,,

COMMENTS