Learn to Program Games for the Atari 2600 in 6502 Assembly Language (1-3 months)

Task: Learn to Program Games for the Atari 2600 in 6502 Assembly Language

Needed: Web browser, Compiler and Emulator Software

Time: 1-3 months

Introduction

A few years ago, I decided to take the plunge and write a game called Gene Medic for the Atari 2600. This turned out to be one of the most frustrating and most rewarding Atari projects I have ever done. I knew it would be a challenge because I needed to solidify my 6502 assembly language programming skills. What I didn’t realize it just how difficult programming for the Atari 2600 would be. Major challenges include the lack of a GPU, limited memory (128 bytes of RAM), and limited program size (4k bytes ROM). The latter two challenges are somewhat obvious and require tight code. However, the biggest challenge is the lack of a GPU which means you need to work around the CPU as it works with the TIA chip to draw the screen. This is really all about timing.

To understand the timing of the CPU you first need to learn how the CPU draws the screen. This is best illustrated in the figure bellow taken from the Stella Programmer’s Guide published in 1979 by Steve Wright. You can see the screen below is divided into 37 + 192 + 30 horizontal scanlines. Each scanline can be thought of as a sweep of the TV’s CRT electron beam scanning across the phosphorescent screen. The 192 scanlines in the middle represent the actual picture and this is where the players, missiles, and playfield of a game are drawn. The Stella guide describes this pretty well. The important thing to know here is that the programmer must keep track of where each scanline is at to draw the picture and to execute code. Further, code can only be executed on each scanline during the horizontal blank (a pause by the CRT) because the CPU is busy when the screen is being drawn. The key is to remember that you can only execute a limited number of assembly language commands so as not to exceed the time allotted in the horizontal blank. This is called cycle counting because each assembly command takes a certain number (e.g. 2 or 3) cycles to execute. Larger and more complex games can require counting every single cycle to squeeze as much game logic out of the system as possible. What all of this means is that it is super easy to throw off the timing of the screen rendering and break the game. There are lots of steps that have to happen in a very particular way.

There are other limitations to the hardware that can limit what you can do in a game. For example, there are only two players, two missiles, and a ball that can be drawn and moved around. This significantly limits what you can do with a game. Further, the playfield has some limitations. Another problem I encountered is that there is no clock to seed a random number generator. I needed to seed it to the position of the player on the screen to get numbers that are close to random. These, and many other important details, are all covered in the tutorials and books I will mention in the Instructions. In addition, I provide below my own ‘kernel’ of the basic elements of an Atari 2600 program so you can see how the program flows through the screen drawing process above.

Instructions

First, I recommend learning or refreshing your knowledge of 6502 assembly language. My last post provides some learning resources.

Second, I recommend reading the Stella Programmer’s Guide to get some of the details of how this all works. This does a good job explaining the hardware details needed to understand the programming required.

Third, read through some of the online tutorials from experts. I particularly like the tutorials by Andrew Davie and Darrel Spice. The latter author has developed and released several popular homebrew games under the label SpiceWare.

Fourth, there are several new books that have been written about programming the 2600. These include “Programming Games for the Atari 2600” by Oscar Toledo and “Making Games for the Atari 2600” by Steven Hugg. Both are about $30 on Amazon. These are wonderful resources to dig a little deeper into the details. Each provides some great examples and some more complex topics such as sound programming which is also not easy.

Fifth, study some Atari 2600 games from back in the day that have been disassembled and commented to so you can see how the masters at the time did it. Some of these can be found at MiniDig. You might be able to find some more through a Google search. One of the other websites that listed these seems to be down (bjars.com).

Sixth, when you are ready to start programming you will need several things. I usually just use a text editor like notepad to write my code. You could also use a more formal IDE. I then save the code as a .asm file and compile with the DASM macro assembler available for Mac, Linux, and Windows. I have previously done a post on this. I use the Windows PowerShell to get a command line and execute DASM with ./dasm.exe “game.asm” -o”game.bin” -f3. This will compile your assembly code into a machine-readable binary file (e.g. .bin) that you can load into the Stella emulator and play. You will likely need vcs.h and macro.h as header files that contain useful commands and code that can be called from your main program. These should be in the same directly when you compile if you use INCLUDE vcs.h and INCLUDE macro.h in your code. Note that the 8bitworkshop site has a Javascript IDE and emulator that you could try for a web-based solution. It also good to load your binary onto an SD card device such as the Harmony Cartridge to test it on original hardware.

Finally, I have reduced my Gene Medic game code to a minimal kernel with heavy commenting to get you started. You could take this code base and start adding to it for your game. Read all the comments. It will help you understand the various pieces and parts to complement what others have done in the resources mentioned above. Below is the commented kernel code. A text file with the code is here.

; ****************************************************************
; An Atari 2600 game kernel by Jason H. Moore, Ph.D.
; Thanks to Andrew Davie, Darrel Spice, and many others who
; provided numerous examples and tutorials that I learned from.
; I used this kernel in my game GeneMedic at http//genemedic.org.
; ****************************************************************

; ****************************************************************
; Tell the assembler we are working with the 6502 processor
; ****************************************************************

PROCESSOR 6502

; ****************************************************************
; Include the vcs header file with the 2600 register and
; memory map definitions. Also include the macro file that
; has some useful functions such as 'sleep'.
; ****************************************************************

INCLUDE VCS.h
INCLUDE macro.h

; ****************************************************************
; Constants set here. This makes code easier to read and is
; converted by assembler to actual values when compiled.
; ****************************************************************

CONSTANT = 1        ; just an example

; ****************************************************************
; Tell the assembler the memory locations of our game variables.
; ds is a pseudo-op for assembler that stands for 'define space'
; ds 1 = one byte and ds 2 = two bytes. Remember that the 2600
; only has 128 bytes of RAM!
; ****************************************************************

SEG.U variables     ; pseudo-op for the assembler
ORG $80             ; the starting location of RAM

VARIABLE ds 1       ; just an example

; ****************************************************************
; Tell the assembler where the origin (ORG) of the program is
; ROM is memory location $F000 to $FFFF
; ****************************************************************

SEG                 ; pseudo-op to set current segment
ORG $F000           ; let the assembler know start address

; ****************************************************************
; This initializes the RAM and TIA registers by writing 0s.
; It also initalizes the stack pointer to $FF. This code comes
; from Andrew Davie's tutorial. Note just clearing the RAM did
; not work well on the original 2600 hardware.
; ****************************************************************

Reset

ldx #0             ; load the X register with a 0
txa                ; transfer X to accumulator

Clear
      dex          ; decrement X register
      txs          ; transfer X to stack pointer
      pha          ; push accumulator onto stack
      bne Clear    ; branch to Clear if accumulator != 0

; ****************************************************************
; The first part of a 2600 program is the vertical sync that
; tells the TV to get ready to draw a picture. The CPU needs
; to wait for three scanlines for the TV to get ready. This
; is done with VSYNC to start this process and WSYNC (x2) to
; wait for the scanlines to finish. Note that VSYNC and WSYNC
; are defined in VCF.h
; ****************************************************************

VerticalSYNC   ; The start of the new frame
               ; Main game loop starts here

lda #2         ; load the accumulator with a 2
sta VSYNC      ; store 2 in VSYNC memory to start
sta WSYNC      ; wait for scanline to finish
sta WSYNC      ; second WSYNC (need at least 2)

lda #0         ; load the accumulator with a 0
sta VSYNC      ; store 0 in VSYNC memory to end

; ****************************************************************
; The second part of a 2600 program is the vertical blank
; with an additional 37 scanlines of time before the screen
; is actually drawn on the TV. Can do some game computations
; here but must count the scanlines to add up to 37 total.
; We will use the X register to count down from 37.
; ****************************************************************

ldx #37                   ; load X register with 37

VerticalBLANK             ; Vertical blank loop

      sta WSYNC           ; wait for scanline to finish
      dex                 ; decrease X
      cpx #0              ; X = 0?
      bne VerticalBLANK   ; loop if X != 0

sta VBLANK                ; store 0 in VBLANK memory to end
                          ; and start drawing the picture by
                          ; turning the TV beam on

; ****************************************************************
; The third part of a 2600 program is the screen drawing routine
; that is often called the kernel. This is where the players,
; missiles, and playfield are drawn. There are 192 scanlines to
; be drawn. We will use the X register to keep track of 192
; scanlines. To draw players and playfields you would read in data
; for each scanline in the ScanlineLoop shown below. More on that
; later. Note that background color variable COLUBK is defined in
; VCF.h.
; ****************************************************************

ldx #192                 ; load X register with 192
                         ; this is the first scanline at top
                         ; of the screen

ScanLineLoop
      stx COLUBK         ; set the background color
      sta WSYNC          ; wait for scanline to finish

      dex                ; Decrease X
      cpx #0             ; X = 0?

      bne ScanLineLoop   ; no, loop again and set next color

; ****************************************************************
; Finally, when the screen is done drawing it enters the overscan
; where scanlines are off the visible screen at bottom. This goes
; on for 30 scanlines. Can do some computation here if needed.
; This is a good place to check for joystick movement, game reset
; presses, and fire button presses. Can also trigger sounds here.
; ****************************************************************

ldx #30                 ; load X register with 37

Overscan                ; Overscan loop

     sta WSYNC          ; wait for scanline to finish
     dex                ; decrease X
     cpx #0             ; X = 0?
     bne Overscan       ; loop if X != 0

jmp VerticalSYNC        ; start the entire process over!

; ****************************************************************
; This area can be used for game data and subroutines called
; from above. Will provide some examples at a later time.
; ****************************************************************

; ****************************************************************
; The Interrupts are used to help rescue the 6502 if it fails.
; 2/3 are not used by the 6507 chip version used in the 2600.
; ****************************************************************

ORG $FFFA            ; address for the interrupt vectors

InterruptVectors

.word Reset          ; NMI
.word Reset          ; RESET
.word Reset          ; IRQ

END

Here is what the executed kernel should look like on Stella. There should be 192 lines of color below.

Executed kernel code
Executed kernel code

Comments

I wish you well on your 2600 game journey! Mine was a long roller coaster of victories and failures. My best advice is to read as many sources as you can, and look at as much code as you can, to find something that makes sense to you and that works.

If you get stuck, you can always consult the AtariAge 2600 programming forum. In most cases there will be a post related to your problem.

I will try to do some more posts with additional examples.