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

How Does One Acquire That Skill, and Me…

On my Dice.com jobs feed today.  I didn’t realize there’s more than one:

dice-feed-072310.1809

~ZagNut

Programming the Atari 2600, and Me – Part 2

Greetings.

Now that we have an IDE set up for creating our 2600 game, we need to know what we’re actually having to program.  Here’s a breakdown of (what I’ve garnered is) the core of the Atari 2600 architecture:

schematic

We have a game cartridge [A], our program ROM.  We have [B], a MOS 6532 RAM / IO/ Timer (RIOT) chip.  [C] is a MOS 6507 microprocessor, practically identical to the 6502 of fame.  Last we have [D], a custom Television Integrated Adapter (TIA) chip designed specifically for the machine.

The links above will give you more than enough information to discern the relationship between these circuits, but in a nutshell, the Atari 2600 basically has 8K of addressable space to work with.  4K is reserved for the RIOT chip, the other 4K for our program.  The RIOT chip generously provides us 128 BYTES (not KILO-bytes, but BYTES for crying out loud) of RAM (0x0080 through 0x00FF), as well as I/O and timer functions (0x0280 through 0x0297), I/O referring to the joysticks, paddles, etc.  If you’ve downloaded DASM, a file VCS.h should have come with it.  This header already has the RIOT and TIA mnemonics mapped out to the appropriate addresses.  The TIA chip handles the presentation “stuff” for us, basically drawing to the TV display and registering collisions and I guess what you could call audio.  In our 8K of addressable space, addresses 0x0000 through 0x003F are TIA chip stuff.  Again, the VCS.h file has these mapped out to their official mnemonics.

I don’t feign to be an electrical engineer or care to be an expert on the internal workings of televisions, because I believe our modern newfangled LCD, projection and plasma HDTVs probably don’t work this way, but at least when the TIA was designed, it was designed to handle synchronizing the game logic and output with the TV’s rasterized method of rendering it’s display.  An electron beam will hit a portion of phosphor on the TV screen, lighting that point to a particular degree of intensity.  It will do this for each of three colors: red, green, and blue (well, and white for luminosity).  Doing this for a color at a particular point is referred to as a color-clock.

The beam will do this across the screen until it is done with the line it is working on (the scan-line), take a moment to reposition back on the other side of the screen at the next line (a duration called the horizontal blank), and then start again.  When all the lines are “finished”, we say a frame has been completed, and when a frame has been completed, the beam returns all the way back kiddy-corner to start a new frame (a duration called the vertical blank).  NTSC-based systems will do 262.5 lines 60-times per second (or 525 interlaced at 30 frames per second), PAL-based systems 312.5 lines at 50-times per second.  There other systems out there (like SECAM, whatever that is), but from here on in this series, I will just be dealing with all things NTSC unless otherwise noted.  Also, these lines-per-frame-per-second numbers are approximate for purposes of this series.  The links provided go to respective Wikipedia articles with much more detail (and accuracy).  We only need to know so much, and the TIA chip takes care of the rest.  :)

…but I digress.

Below is a simple diagram of how my aging brain is grokking all this (it could therefore obviously be incredibly wrong):

cycles

With the TV knowledge and this delicious diagram in hand, we now can see how we bridge the TV and gaming platform gap via the TIA chip.  The “motherboard” is architected such that a machine cycle – the unit of time used for measuring the duration of a completed 6507 instruction – equals the time it takes for all the colors for a given point on the TV (do not think pixel; analog TVs apparently do not have pixels) to be scanned.  That is, scanning a set of color-clocks for one point on the screen equals a machine cycle, and machine cycles are how we measure program execution timing.  So, if the 6507 chip takes 2 machine cycles to perform an instruction – say, LDA #5, or Load-Accumulator with integer 5 – and a given point on a scan line is made up of 3 (or 4 counting the white luminescence one) color-clocks, then that LDA instruction will take the equivalent of 6 color-clocks to complete.  This leads us to another important image:

cycles2

We see that, according to the TIA, we have 228 color-clocks before a scan line is “finished”: 68 for the horizontal blank, and 160 for the actual TV picture.  The first 3 scan lines perform a vertical sync, then 37 more account for the vertical blank.  The next 192 are our display lines.  A final 30 are overscan lines.  Also, the TIA is synchronized such that 3 color-clocks equal one machine cycle.  Therefore, in the time a TV completes a scan line and returns to the next line, 76 machine cycles will have occurred.  That’s at most 38 instructions.  And we have 262 of these we can do before the process starts all over again, less than 10,000 instructions.  Sweet.

So, a quick recap of this concept: game logic processing by the 6507 is literally in sync with the rasterization process of the TV.  The TIA chip is our bridge between what the 6507 is doing and what the TV is doing.  Ergo, while your program is executing, the TV is scanning lines, so your program itself needs to take this into account and know when as well as what to tell the TV to do while its scanning.

We actually have a bunch more constraints believe it or not.  Just positioning something horizontally is kind of a nightmare.  Basically, you have to write to a register on the TIA when you want the object to appear at the same time on the following scan line.  We’ll get to that giant ugly later.  For now, I, like you, will sit and zen on this a bit.  We’ll pick up next time from here and actually look at executing some code in Stella.  In the meantime, here are several good links / documents / tools to start looking at:

  • AtariAge – This seems to be a de facto site for Atari 2600 enthusiasts and programmers
  • 6502 simulator – Excellent tool for testing your 65xx code.  Really helps for developing small routines like random number generators.
  • 2600 Programmer’s Guide – Our bible from now on.  This is a much better version, but my advice is print out the former because chicks will dig it when they see it…
  • TIA documentation - ‘nuff said.
  • All 2600 specs ever (it seems) – Crazy good site documenting the 2600.

 

~ZagNut

«July»
SunMonTueWedThuFriSat
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567