T.M.R's 2600 Rant (An Introduction To Homebrew On The Atari 2600)
Article By T.M.R
The Atari 2600 is probably one of the lowest specification machines that a homebrew developer could choose to work on, but at the same time that makes it one of the most desirable for the overall challenge offered by the finite hardware, close to non-existent RAM and limited ROM space. But appreciating just how much work goes into an Atari 2600 game, how much magic is actually being performed, does require at least a limited understanding of the machine and the hoops being jumped through by the programmers. I'm not a 2600 developer myself, however I've worked with it and produced some (to date incomplete) programs, the following is based on my understanding of the basics from those excursions. A little technical background will probably be useful too, but I'll try to avoid getting too tied up in those details.
So, the first and most obvious problem with working with the Atari 2600 is how little space you actually get; the biggest size for a cartridge without bank switching and the biggest space available even if you are is 4K of ROM, which is seated right at the top of the 6507's address space. That's augmented, for want of a better word, by a mere 128 bytes of RAM from the 256 the hardware has and yes, you did read that correctly, a mere 128 bytes down in the first 256 byte page with the rest of that space given over to registers for video, audio, joystick input and so forth. In other words, just about everything from level designs to sprite definitions has to come from that 4K of ROM and the RAM is only used for keeping tabs on whatever changes throughout play; sprite positions, scores, anything that can't be set in stone or at least in ROM. To give an idea of scale, the first sentence in this article is over 280 bytes and would fill the entire RAM twice, whilst the entire article is over 11K long and would require three standard cartridges to store!
There are several bank switching schemes to allow more ROM (and in a few cases, RAM) within a cartridge, but they and the 2600 hardware introduce new... quirks to the mix at the same time; since the 6507, the processor used by the 2600 and a relation of the 6502 used in Atari 8-bit home computers, can't address more than 4K at a time the cartridge instead switches the data it has in and out in banks of 4K; that means that at the flip of a virtual switch, either the entire 4K is totally replaced with another bank in one pass (which means that the new bank needs to "catch" the processor by having code where the program counter was up to) or leaving one half of the space fixed whilst the other changes. And at least one byte of precious RAM is needed to tell the cartridge which block is currently in use... and if that wasn't bad enough, every manufacturer had their own variation on the theme and there's no standard!
Next there's the display hardware - and I'm using the phrase in a very loose way since there's not a fat lot of it! One of the main considerations when designing the 2600 was cost, which explains the minute RAM and the miniscule ROM space since both were hideously expensive at the time, but that lack of memory means that there's no frame buffer and programs are given the job of handling construction of the screen themselves. The screen does get some of the RAM assigned to it, but it's a paltry two and a half bytes worth. The screen is forty pixels wide (yes you did read that correctly again, pixels and they're about half the width of one hardware sprite), and twenty of the twenty four bits from those three bytes directly powers the display, if a bit is set then a pixel appears, otherwise the background shows through. Then, depending on the mode the video hardware (called the Television Interface Adapter, or just TIA from here onwards) has been set to, it either repeats those twenty pixels for the right half of the display or mirrors them. And simply setting those bytes merely causes the values to stripe down the screen (that's why you'll sometimes stripes when you reset a 2600, the program is no longer feeding data to the TIA for the display, so it just keeps churning out what's currently in the RAM) so to build actual screens of mazes, jungles, caves or whatever requires the program to write to those bytes each time the display needs to be changed; assuming that square pixels are the order of the day, that means changing those three bytes once every eight raster lines as the display is being drawn and those values with be retained until they're next changed.
So you might be asking yourself how some games create an asymmetrical playfield since you've seen it done and I've just told you the hardware only mirrors or repeats the right-hand part of the display? Well, this is where things start getting fun because in order to do that you need to write to all three bytes of the screen memory twice a scanline, once to set it for the left half of the playfield and again to set it for the right; on most other machines that kind of vertical splitting is considered advanced demo coding techniques, but for the 2600 it's the norm!
Thankfully, the 2600 does have some hardware sprites (but not as we know them, Jim...); there are two players (which are eight pixels wide and can be set to expand or repeat themselves up to three times), two missiles and a "ball" object and the pixels in question are four times the resolution of the playfield, one player is the same width as two pixels on the background. Again, there isn't any RAM to actually store shapes for any of that lot, instead they have a couple of bytes of RAM assigned for the player definitions and some trigger bytes for the missiles and ball which means that they don't even get shapes as such like the players do, just the option to be on or off! Players are the full height of the screen in the same way that the Atari 8-bits do it, but have one byte each for actual shapes rather than a block of memory to write to... so yes, for the second time we're writing data in on a scanline-by-scanline basis, except this time there's a wait until the object starts, a flurry of activity for however many scanlines high it is, then nothing again until either the sprite is recycled (not easy, but it can be done) or we reach the bottom of the screen!
As if that wasn't bad enough (and it's fiddly as hell keeping an eye on all the timers and exceptions whilst simultaneously displaying everything else with only an accumulator and two registers) the horizontal positioning of these objects is actually more complex because there's no X position register for any of the sprites, Instead the program has to wait until it gets to the right processor cycle of the current scanline (again, using a technique that would be considered advanced demo code elsewhere) and write to a latch register in order to roughly position a sprite and all objects in use need this doing, so that's a maximum five scanlines required if every sprite is active although it can at least happen in the "dead" space above the top of the screen display itself. But this process is fairly inaccurate, so along with the latch there are "nudge" registers that can move a sprite left or right a few pixels; the distances for all objects can be set and then a flag written to in order to let the TIA know it's time to nudge. The TIA checks that flag at the start of the next scanline and immediately shunts all the sprites into their new places but there is a side effect; if you've ever watched 2600 games in attract mode (or those with coloured rather than black backgrounds) you might have seen some horizontal black lines at the left of the playfield about the width of the players, that's the TIA dropping out for a few cycles in order to do the work.
Oh, those games that have things like five or six digit scores that are too high a resolution to be constructed by the 40 pixel playfield? They're actually using the replication mode of the sprites so there is a block of six objects (the first sprite does the odd-numbered columns, the second the even and there are 8 pixel gaps so they can dovetail together) and then splitting the sprite data three times a scanline for each sprite! that's why a lot of games have the score bar all bunched together or rely at least in part on large, chunky scores built from the playfield.
Sound is also produced by the TIA (again, that's partly due to the way the 2600 was designed to keep the component count down and less common but not unheard of with 8-bits) and is limited to two channels; each works independently, has fifteen volume levels not including silence and the generators can be configured to produce sounds ranging from a pure "flute" to assorted variations on tone and noise for explosion sounds and so forth. What makes it harder to work with is the way that the generators interfere with each other, attempting to play music is therefore difficult because playing two notes on the two generators causes both to go off kilter with the shift being governed by the notes themselves. Also, selecting a waveform is a pretty random affair and is best done with experimentation.
So to give a very rough idea, even for something (relatively) simple there will be three bytes written every eight scanlines for the playfield and up to four bytes per scanline to draw the two tanks and set positions for their missiles. The main loop of the program waits for just before the end of what will be the upper border, does some housekeeping to get everything ready to display, roughly and then finely positions the players and missiles, waits for the start of the screen itself and then spends about a hundred and ninety two scanlines spooling out data as the raster scan passes down, counting off to the points where it needs to draw in the player definitions or trigger the missiles. Finally, it gets to the bottom of the display area, blanks everything off to leave it neat down there and uses the remaining time to actually handle the game elements and logic, update the sound and generally juggle the game itself. For something more complex with an asymmetrical display, there will be six bytes written per scanline in for any lines that are displaying playfield graphics as well as the sprite data and, assuming there is a need for colour changes to either the sprites or the playfield, they will need to take place in at the appropriate places as well.
To be honest, this article doesn't actually make it sound as complex to work with as it actually is and jobs that would usually be considered relatively simple on an 8-bit such as displaying a static playfield or even the positioning of a sprite are actually pretty difficult to achieve even with the far easier to use cross assembly to emulation environments now available to homebrew coders. At the same time, that complexity that comes from the 2600's simplicity is pretty much what makes the Atari 2600 as popular as it is for programmers and, whilst it probably isn't the best machine to learn 6502 programming on and can give even more experienced programmers a run for their money, that challenge drives people to take the beast and attempt to tame it.